mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-28 09:02:12 +08:00
* feat(cli): add unified Commander CLI for QingLong 2.x * fix(cli): publish via npm and address security review feedback * ci(cli): package npm artifacts and remove evaluation collateral * test(cli): use a fixed shell fixture for log retention * refactor(cli): separate remote npm client from panel tools * feat(cli): cover active panel OpenAPI resources * docs(cli): unify authentication and skill guidance * refactor(cli): isolate internal commands and generate Commander help * refactor(cli): organize remote and internal modules by responsibility * ci(cli): publish verified npm archives from master * fix(cli): publish under the whyour npm scope * ci: use npm trusted publishing for both packages * docs: introduce the published CLI on the project homepage * fix(cli): preserve server log truncation and correct login hints * fix(cli): accept dashboard record request bodies * fix(cli): preserve stdin for local task execution * fix(cli): resolve task executables after changing directory * fix(cli): preserve shell function tasks and sanitize test failures * fix(cli): preserve shell hook state and resolve workdir after hooks * fix(cli): preserve cleanup across shared shell task timeouts * fix(cli): isolate shell control descriptors and reap timed-out descendants
52 lines
1.7 KiB
TypeScript
52 lines
1.7 KiB
TypeScript
import fs from 'node:fs/promises';
|
|
import path from 'node:path';
|
|
import type { LocalContext } from './context';
|
|
|
|
// The released 2.20 API rejects unknown lifecycle fields and has no dashboard record API.
|
|
// Read the installed panel version, never the independently versioned CLI package.
|
|
export async function extendedLifecycle(
|
|
context: LocalContext,
|
|
): Promise<boolean> {
|
|
if (context.env.QL_CLI_LIFECYCLE === 'legacy') return false;
|
|
if (context.env.QL_CLI_LIFECYCLE === 'extended') return true;
|
|
let version: string | undefined;
|
|
try {
|
|
const manifest: unknown = JSON.parse(
|
|
await fs.readFile(path.join(context.root, 'package.json'), 'utf8'),
|
|
);
|
|
if (
|
|
manifest &&
|
|
typeof manifest === 'object' &&
|
|
'version' in manifest &&
|
|
typeof manifest.version === 'string'
|
|
)
|
|
version = manifest.version;
|
|
} catch {}
|
|
if (version === undefined) {
|
|
try {
|
|
// Official 2.x images may omit package.version. Read only the top-level
|
|
// scalar release field; no YAML dependency or expression evaluation.
|
|
const release = await fs.readFile(
|
|
path.join(context.root, 'version.yaml'),
|
|
'utf8',
|
|
);
|
|
const entries = release
|
|
.replace(/^\uFEFF/, '')
|
|
.split(/\r?\n/)
|
|
.filter((line) => /^version:/.test(line));
|
|
if (entries.length !== 1) return false;
|
|
const scalar =
|
|
/^version:[ \t]*(?:"([^"]+)"|'([^']+)'|([^\s#]+))[ \t]*(?:#.*)?$/.exec(
|
|
entries[0]!,
|
|
);
|
|
version = scalar?.[1] ?? scalar?.[2] ?? scalar?.[3];
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
const match = /^2\.(\d+)\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.exec(
|
|
version ?? '',
|
|
);
|
|
return !!match && Number(match[1]) >= 21;
|
|
}
|