@anieo/codegenie-cli 0.0.0-develop-202604071142 → 0.0.0-develop-202604072034

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,57 @@
1
+ # CodeGenie CLI
2
+
3
+ `CodeGenie` 是面向 HarmonyOS 开发场景的 AI CLI。
4
+
5
+ ## 安装
6
+
7
+ ```bash
8
+ npm install -g @anieo/codegenie-cli
9
+ ```
10
+
11
+ 预发布渠道:
12
+
13
+ ```bash
14
+ npm install -g @anieo/codegenie-cli@beta
15
+ npm install -g @anieo/codegenie-cli@alpha
16
+ ```
17
+
18
+ 安装完成后即可直接执行:
19
+
20
+ ```bash
21
+ codegenie --version
22
+ ```
23
+
24
+ 说明:
25
+
26
+ - npm 安装会直接创建全局 `codegenie` 命令
27
+ - 如果 npm 因 optionalDependencies 配置跳过了平台包,安装脚本会自动补装当前平台包
28
+ - npm 安装阶段会预热 runtime assets;Windows 还会额外隐藏预热一次默认启动路径,因此安装时间会略长,但首次可见启动会更快
29
+ - 首次运行通常不再需要解包和安装依赖;首次进入某个工作区时,仍可能有少量项目级初始化
30
+ - 首次运行不会再把二进制复制到 `~/.codegenie/bin`
31
+ - npm 安装/升级会清理旧安装残留和临时更新残留
32
+ - `upgrade` 在 npm 安装场景下会提示或委托执行 npm 升级命令,不直接覆写 npm 全局目录
33
+
34
+ ## 卸载
35
+
36
+ 推荐顺序:
37
+
38
+ ```bash
39
+ codegenie uninstall --yes
40
+ npm uninstall -g @anieo/codegenie-cli
41
+ ```
42
+
43
+ 说明:
44
+
45
+ - `codegenie uninstall --yes` 删除 `~/.codegenie` 运行目录
46
+ - `npm uninstall -g @anieo/codegenie-cli` 删除 npm 全局命令和包记录
47
+ - npm 卸载生命周期脚本会做最佳努力清理,但不同 npm 版本行为不完全一致,不应只依赖 `npm uninstall -g`
48
+
49
+ ## 平台说明
50
+
51
+ 当前 staged 平台包:`@anieo/codegenie-cli-darwin-arm64`
52
+
53
+ - `baseline` 兼容构建不进入 npm 正式发布范围
54
+
55
+ ## 发布说明
56
+
57
+ 仓库中的 `packages/npm/codegenie` 为元包模板。正式发布前请先运行仓库脚本生成 `dist/npm/` 下的 publishable 包,再按发布顺序上传各平台包和元包。
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { spawn } = require("child_process")
4
+ const { buildLaunchEnv } = require("../lib/launch.js")
5
+ const { resolveBinary } = require("../lib/resolve-binary.js")
6
+ const { shouldPrintStartupHint, startupHintText } = require("../lib/startup-hint.js")
7
+
8
+ const SPINNER = ["\u2807", "\u280B", "\u2819", "\u2838", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"]
9
+
10
+ function main() {
11
+ const argv = process.argv.slice(2)
12
+ const showHint = shouldPrintStartupHint(argv)
13
+
14
+ let spinnerInterval = null
15
+ let spinnerIdx = 0
16
+ if (showHint && process.stderr.isTTY) {
17
+ process.stderr.write("\x1b[?25l")
18
+ const draw = () => {
19
+ process.stderr.write(`\r \x1b[36m\x1b[1mCodeGenie\x1b[0m \x1b[2m${SPINNER[spinnerIdx++ % SPINNER.length]} Loading...\x1b[0m`)
20
+ }
21
+ draw()
22
+ spinnerInterval = setInterval(draw, 100)
23
+ } else if (showHint) {
24
+ process.stderr.write(startupHintText() + "\n")
25
+ }
26
+
27
+ const resolved = resolveBinary()
28
+
29
+ const child = spawn(resolved.binaryPath, argv, {
30
+ stdio: "inherit",
31
+ env: buildLaunchEnv(resolved.packageName, resolved.platformDir, process.env),
32
+ })
33
+
34
+ child.on("spawn", () => {
35
+ if (spinnerInterval) {
36
+ clearInterval(spinnerInterval)
37
+ spinnerInterval = null
38
+ }
39
+ })
40
+
41
+ child.on("error", (err) => {
42
+ if (spinnerInterval) {
43
+ clearInterval(spinnerInterval)
44
+ }
45
+ process.stderr.write("\r\x1b[K\x1b[?25h")
46
+ console.error(`[codegenie] Failed to start ${resolved.packageName}: ${err.message}`)
47
+ process.exit(1)
48
+ })
49
+
50
+ child.on("exit", (code, signal) => {
51
+ if (spinnerInterval) {
52
+ clearInterval(spinnerInterval)
53
+ }
54
+ if (signal) {
55
+ process.kill(process.pid, signal)
56
+ } else {
57
+ process.exit(code ?? 1)
58
+ }
59
+ })
60
+
61
+ function forwardSignal(sig) {
62
+ if (child.pid) child.kill(sig)
63
+ }
64
+ process.on("SIGINT", forwardSignal)
65
+ process.on("SIGTERM", forwardSignal)
66
+ }
67
+
68
+ main()
@@ -0,0 +1,83 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { execFileSync } = require("child_process")
4
+ const { resolveBinary, resolvePackageName } = require("../lib/resolve-binary.js")
5
+ const { prewarmBinary, warmStartupBinary } = require("../lib/prewarm.js")
6
+ const packageJson = require("../package.json")
7
+
8
+ function tryInstallPlatformPackage() {
9
+ let platformPackageName
10
+ try {
11
+ platformPackageName = resolvePackageName()
12
+ } catch {
13
+ return false
14
+ }
15
+
16
+ const platformVersion = packageJson.optionalDependencies && packageJson.optionalDependencies[platformPackageName]
17
+ const installSpec = platformVersion ? `${platformPackageName}@${platformVersion}` : platformPackageName
18
+ const npmExecutable = process.platform === "win32" ? "npm.cmd" : "npm"
19
+
20
+ console.log(`[codegenie] Platform package ${platformPackageName} not found, attempting to install...`)
21
+ try {
22
+ execFileSync(npmExecutable, ["install", "-g", installSpec], {
23
+ stdio: "inherit",
24
+ timeout: 120000,
25
+ })
26
+ return true
27
+ } catch (err) {
28
+ console.warn(`[codegenie] Failed to auto-install ${installSpec}: ${err && err.message ? err.message : String(err)}`)
29
+ return false
30
+ }
31
+ }
32
+
33
+ function runPostInstall() {
34
+ let resolved
35
+ try {
36
+ resolved = resolveBinary()
37
+ } catch (firstError) {
38
+ const attempted = tryInstallPlatformPackage()
39
+ if (!attempted) {
40
+ const message = firstError && firstError.message ? firstError.message : String(firstError)
41
+ console.warn("[codegenie] npm install completed, but platform binary verification will be deferred to first launch.")
42
+ console.warn(message)
43
+ return
44
+ }
45
+ try {
46
+ resolved = resolveBinary()
47
+ } catch (retryError) {
48
+ const message = retryError && retryError.message ? retryError.message : String(retryError)
49
+ console.warn("[codegenie] npm install completed, but platform binary verification will be deferred to first launch.")
50
+ console.warn(message)
51
+ return
52
+ }
53
+ }
54
+
55
+ console.log("[codegenie] npm install complete. Global command \"codegenie\" is ready.")
56
+ console.log(`[codegenie] Using platform package ${resolved.packageName}.`)
57
+ console.log("[codegenie] Prewarming runtime assets during npm install...")
58
+ let result = prewarmBinary(resolved.binaryPath, resolved.platformDir)
59
+ if (result.error || (typeof result.status === "number" && result.status !== 0)) {
60
+ const reason = result.error ? result.error.message : `exit code ${result.status}`
61
+ console.warn(`[codegenie] Runtime prewarm attempt 1 failed (${reason}), retrying...`)
62
+ result = prewarmBinary(resolved.binaryPath, resolved.platformDir)
63
+ }
64
+ if (result.error) {
65
+ console.warn(`[codegenie] Runtime prewarm failed: ${result.error.message}`)
66
+ } else if (typeof result.status === "number" && result.status !== 0) {
67
+ console.warn(`[codegenie] Runtime prewarm exited with code ${result.status}. First launch will finish initialization.`)
68
+ } else {
69
+ console.log("[codegenie] Runtime assets are ready. First launch should be faster.")
70
+ }
71
+
72
+ if (process.platform === "win32" && process.env.CODEGENIE_SKIP_WARM_STARTUP !== "true") {
73
+ console.log("[codegenie] Finalizing hidden first-launch warmup...")
74
+ const startupWarm = warmStartupBinary(resolved.binaryPath, resolved.platformDir)
75
+ if (startupWarm.error) {
76
+ console.warn(`[codegenie] Hidden startup warmup failed: ${startupWarm.error.message}`)
77
+ } else if (typeof startupWarm.status === "number" && startupWarm.status !== 0) {
78
+ console.warn(`[codegenie] Hidden startup warmup exited with code ${startupWarm.status}. First visible launch may still be slower.`)
79
+ }
80
+ }
81
+ }
82
+
83
+ runPostInstall()
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { cleanupAfterNpmUninstall, cleanupLegacyLoginState } = require("../lib/cleanup.js")
4
+
5
+ try {
6
+ const result = cleanupAfterNpmUninstall()
7
+ if (result.removed) {
8
+ console.log(`[codegenie] Removed runtime directory: ${result.rootDir}`)
9
+ } else if (result.reason === "package-mismatch") {
10
+ console.log(`[codegenie] Skip runtime cleanup because install context belongs to another npm package.`)
11
+ } else if (result.reason === "missing") {
12
+ console.log("[codegenie] Runtime directory already removed.")
13
+ } else if (result.reason === "remove-failed") {
14
+ const hint = result.error && result.error.message ? ` (${result.error.message})` : ""
15
+ console.warn(`[codegenie] Failed to remove runtime directory${hint}. Remove manually: ${result.rootDir}`)
16
+ }
17
+
18
+ if (result.removed || result.reason === "missing") {
19
+ const legacyState = cleanupLegacyLoginState()
20
+ if (legacyState.removed) {
21
+ console.log(`[codegenie] Removed legacy login state: ${legacyState.path}`)
22
+ } else if (legacyState.reason === "remove-failed") {
23
+ const hint = legacyState.error && legacyState.error.message ? ` (${legacyState.error.message})` : ""
24
+ console.warn(`[codegenie] Failed to remove legacy login state${hint}. Remove manually: ${legacyState.path}`)
25
+ }
26
+ }
27
+ } catch (error) {
28
+ const message = error && error.message ? error.message : String(error)
29
+ console.warn(`[codegenie] Runtime cleanup during npm uninstall failed: ${message}`)
30
+ }
package/lib/cleanup.js ADDED
@@ -0,0 +1,121 @@
1
+ const fs = require("fs")
2
+ const os = require("os")
3
+ const path = require("path")
4
+
5
+ function runtimePaths(homeDir = os.homedir()) {
6
+ const rootDir = path.join(homeDir, ".codegenie")
7
+ const binDir = path.join(rootDir, "bin")
8
+ return {
9
+ rootDir,
10
+ binDir,
11
+ binaryPath: path.join(binDir, process.platform === "win32" ? "codegenie.exe" : "codegenie"),
12
+ installContextPath: path.join(rootDir, "install-context.json"),
13
+ }
14
+ }
15
+
16
+ function legacyLoginStatePath(homeDir = os.homedir()) {
17
+ return path.join(homeDir, ".config", "ts-login")
18
+ }
19
+
20
+ function isRecord(value) {
21
+ return typeof value === "object" && value !== null
22
+ }
23
+
24
+ function belongsToExpectedPackageFamily(actualPackageName, expectedPackageName) {
25
+ return actualPackageName === expectedPackageName || actualPackageName.startsWith(`${expectedPackageName}-`)
26
+ }
27
+
28
+ function readInstallContext(homeDir = os.homedir()) {
29
+ try {
30
+ const raw = JSON.parse(fs.readFileSync(runtimePaths(homeDir).installContextPath, "utf-8"))
31
+ if (!isRecord(raw)) return null
32
+ if (raw.installSource !== "npm" && raw.installSource !== "standalone") return null
33
+ return {
34
+ installSource: raw.installSource,
35
+ npmPackageName:
36
+ typeof raw.npmPackageName === "string" && raw.npmPackageName.trim() ? raw.npmPackageName.trim() : null,
37
+ }
38
+ } catch {
39
+ return null
40
+ }
41
+ }
42
+
43
+ function removeWithRetry(targetPath, maxRetries = 2) {
44
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
45
+ try {
46
+ fs.rmSync(targetPath, { recursive: true, force: true })
47
+ return { success: true, error: null }
48
+ } catch (err) {
49
+ const code = err && err.code
50
+ if ((code === "EBUSY" || code === "EPERM") && attempt < maxRetries) {
51
+ const delay = (attempt + 1) * 500
52
+ const end = Date.now() + delay
53
+ while (Date.now() < end) { /* busy wait */ }
54
+ continue
55
+ }
56
+ return { success: false, error: err }
57
+ }
58
+ }
59
+ return { success: false, error: null }
60
+ }
61
+
62
+ function cleanupAfterNpmUninstall(options = {}) {
63
+ const homeDir = options.homeDir || os.homedir()
64
+ const expectedPackageName =
65
+ options.expectedPackageName || process.env.CODEGENIE_NPM_PACKAGE || process.env.npm_package_name || null
66
+ const paths = runtimePaths(homeDir)
67
+ const context = readInstallContext(homeDir)
68
+
69
+ if (
70
+ context &&
71
+ expectedPackageName &&
72
+ context.npmPackageName &&
73
+ context.installSource === "npm" &&
74
+ !belongsToExpectedPackageFamily(context.npmPackageName, expectedPackageName)
75
+ ) {
76
+ return { removed: false, reason: "package-mismatch", rootDir: paths.rootDir }
77
+ }
78
+
79
+ if (!fs.existsSync(paths.rootDir)) {
80
+ return { removed: false, reason: "missing", rootDir: paths.rootDir }
81
+ }
82
+
83
+ const result = removeWithRetry(paths.rootDir)
84
+ if (!result.success) {
85
+ return {
86
+ removed: false,
87
+ reason: "remove-failed",
88
+ rootDir: paths.rootDir,
89
+ error: result.error,
90
+ }
91
+ }
92
+ return { removed: true, reason: "removed", rootDir: paths.rootDir }
93
+ }
94
+
95
+ function cleanupLegacyLoginState(options = {}) {
96
+ const homeDir = options.homeDir || os.homedir()
97
+ const targetPath = legacyLoginStatePath(homeDir)
98
+ if (!fs.existsSync(targetPath)) {
99
+ return { removed: false, reason: "missing", path: targetPath }
100
+ }
101
+ const result = removeWithRetry(targetPath)
102
+ if (!result.success) {
103
+ return {
104
+ removed: false,
105
+ reason: "remove-failed",
106
+ path: targetPath,
107
+ error: result.error,
108
+ }
109
+ }
110
+ return { removed: true, reason: "removed", path: targetPath }
111
+ }
112
+
113
+ module.exports = {
114
+ belongsToExpectedPackageFamily,
115
+ cleanupAfterNpmUninstall,
116
+ cleanupLegacyLoginState,
117
+ legacyLoginStatePath,
118
+ readInstallContext,
119
+ removeWithRetry,
120
+ runtimePaths,
121
+ }
package/lib/launch.js ADDED
@@ -0,0 +1,18 @@
1
+ const packageJson = require("../package.json")
2
+
3
+ function buildLaunchEnv(resolvedPackageName, platformDir, baseEnv = process.env) {
4
+ const env = {
5
+ ...baseEnv,
6
+ CODEGENIE_INSTALL_SOURCE: "npm",
7
+ CODEGENIE_NPM_PACKAGE: packageJson.name,
8
+ CODEGENIE_NPM_PLATFORM_PACKAGE: resolvedPackageName,
9
+ }
10
+ if (platformDir) {
11
+ env.CODEGENIE_NPM_PLATFORM_DIR = platformDir
12
+ }
13
+ return env
14
+ }
15
+
16
+ module.exports = {
17
+ buildLaunchEnv,
18
+ }
package/lib/prewarm.js ADDED
@@ -0,0 +1,78 @@
1
+ const fs = require("fs")
2
+ const os = require("os")
3
+ const { spawnSync } = require("child_process")
4
+
5
+ function buildPrewarmEnv(platformDir, baseEnv = process.env) {
6
+ const env = {
7
+ ...baseEnv,
8
+ CODEGENIE_PREPARE_ONLY: "true",
9
+ CODEGENIE_INSTALL_SOURCE: "npm",
10
+ CODEGENIE_NPM_PACKAGE:
11
+ baseEnv.CODEGENIE_NPM_PACKAGE || baseEnv.npm_package_name || "codegenie",
12
+ }
13
+ if (platformDir) {
14
+ env.CODEGENIE_NPM_PLATFORM_DIR = platformDir
15
+ }
16
+ return env
17
+ }
18
+
19
+ function prewarmBinary(binaryPath, platformDir, spawnImpl = spawnSync, baseEnv = process.env) {
20
+ return spawnImpl(binaryPath, [], {
21
+ stdio: "ignore",
22
+ timeout: 120000,
23
+ env: buildPrewarmEnv(platformDir, baseEnv),
24
+ })
25
+ }
26
+
27
+ function buildStartupWarmEnv(platformDir, baseEnv = process.env) {
28
+ const env = {
29
+ ...baseEnv,
30
+ CODEGENIE_WARM_STARTUP: "true",
31
+ CODEGENIE_WARM_STARTUP_TIMEOUT_MS: baseEnv.CODEGENIE_WARM_STARTUP_TIMEOUT_MS || "10000",
32
+ CODEGENIE_INSTALL_SOURCE: "npm",
33
+ CODEGENIE_NPM_PACKAGE:
34
+ baseEnv.CODEGENIE_NPM_PACKAGE || baseEnv.npm_package_name || "codegenie",
35
+ OPENCODE_DISABLE_AUTOUPDATE: "true",
36
+ }
37
+ if (platformDir) {
38
+ env.CODEGENIE_NPM_PLATFORM_DIR = platformDir
39
+ }
40
+ return env
41
+ }
42
+
43
+ function resolveWarmupCwd(baseEnv = process.env, existsImpl = fs.existsSync) {
44
+ const initCwd = typeof baseEnv.INIT_CWD === "string" ? baseEnv.INIT_CWD.trim() : ""
45
+ if (initCwd && existsImpl(initCwd)) {
46
+ return initCwd
47
+ }
48
+
49
+ const userProfile = typeof baseEnv.USERPROFILE === "string" ? baseEnv.USERPROFILE.trim() : ""
50
+ if (userProfile) {
51
+ return userProfile
52
+ }
53
+
54
+ const home = typeof baseEnv.HOME === "string" ? baseEnv.HOME.trim() : ""
55
+ if (home) {
56
+ return home
57
+ }
58
+
59
+ return os.homedir()
60
+ }
61
+
62
+ function warmStartupBinary(binaryPath, platformDir, spawnImpl = spawnSync, baseEnv = process.env, existsImpl = fs.existsSync) {
63
+ return spawnImpl(binaryPath, [], {
64
+ stdio: "ignore",
65
+ timeout: 20000,
66
+ windowsHide: true,
67
+ cwd: resolveWarmupCwd(baseEnv, existsImpl),
68
+ env: buildStartupWarmEnv(platformDir, baseEnv),
69
+ })
70
+ }
71
+
72
+ module.exports = {
73
+ buildPrewarmEnv,
74
+ buildStartupWarmEnv,
75
+ prewarmBinary,
76
+ resolveWarmupCwd,
77
+ warmStartupBinary,
78
+ }
@@ -0,0 +1,107 @@
1
+
2
+ const fs = require("fs")
3
+ const path = require("path")
4
+
5
+ function loadPlatformMap() {
6
+ const platformMapPath = path.join(__dirname, "..", "platform-map.json")
7
+ return JSON.parse(fs.readFileSync(platformMapPath, "utf8"))
8
+ }
9
+
10
+ function detectLibc() {
11
+ if (process.platform !== "linux") return null
12
+ if (process.report && typeof process.report.getReport === "function") {
13
+ const report = process.report.getReport()
14
+ if (report && report.header && report.header.glibcVersionRuntime) {
15
+ return "glibc"
16
+ }
17
+ }
18
+ return "musl"
19
+ }
20
+
21
+ function resolvePackageName() {
22
+ const platformMap = loadPlatformMap()
23
+ const libc = detectLibc()
24
+
25
+ let platformKey = null
26
+ if (process.platform === "darwin" && process.arch === "arm64") platformKey = "darwin-arm64"
27
+ else if (process.platform === "darwin" && process.arch === "x64") platformKey = "darwin-x64"
28
+ else if (process.platform === "linux" && process.arch === "arm64" && libc === "musl") platformKey = "linux-arm64-musl"
29
+ else if (process.platform === "linux" && process.arch === "arm64") platformKey = "linux-arm64"
30
+ else if (process.platform === "linux" && process.arch === "x64" && libc === "musl") platformKey = "linux-x64-musl"
31
+ else if (process.platform === "linux" && process.arch === "x64") platformKey = "linux-x64"
32
+ else if (process.platform === "win32" && process.arch === "x64") platformKey = "win32-x64"
33
+
34
+ if (platformKey && platformMap[platformKey]) {
35
+ return platformMap[platformKey]
36
+ }
37
+
38
+ const libcSuffix = libc ? `/${libc}` : ""
39
+ throw new Error(`Unsupported npm platform: ${process.platform}/${process.arch}${libcSuffix}`)
40
+ }
41
+
42
+ function resolvePlatformPackageDir(packageName) {
43
+ const packageJsonPath = require.resolve(`${packageName}/package.json`)
44
+ return path.dirname(packageJsonPath)
45
+ }
46
+
47
+ function ensureExecutable(binaryPath) {
48
+ if (process.platform === "win32") {
49
+ return
50
+ }
51
+ try {
52
+ const stats = fs.statSync(binaryPath)
53
+ const mode = stats.mode & 0o777
54
+ if (mode !== 0o755 && mode !== 0o775 && mode !== 0o777) {
55
+ fs.chmodSync(binaryPath, 0o755)
56
+ }
57
+ } catch {
58
+ // ignore permission check failure
59
+ }
60
+ }
61
+
62
+ function resolveBinary() {
63
+ const packageName = resolvePackageName()
64
+ let platformDir = ""
65
+ try {
66
+ platformDir = resolvePlatformPackageDir(packageName)
67
+ } catch (error) {
68
+ const metaPackageName = (() => {
69
+ try { return require("../package.json").name } catch { return null }
70
+ })() || process.env.npm_package_name || "@hippox/codegenie"
71
+ const hint = [
72
+ `[codegenie] Failed to locate installed binary package for ${process.platform}/${process.arch}.`,
73
+ `[codegenie] Expected package: ${packageName}`,
74
+ `[codegenie] Reinstall with \`npm install -g ${metaPackageName}\`.`,
75
+ `[codegenie] If your npm disables optionalDependencies, install \`${packageName}\` manually and retry.`,
76
+ ].join("\n")
77
+ const wrapped = new Error(hint)
78
+ wrapped.cause = error
79
+ throw wrapped
80
+ }
81
+
82
+ const binaryPath = path.join(
83
+ platformDir,
84
+ "bin",
85
+ process.platform === "win32" ? "codegenie.exe" : "codegenie",
86
+ )
87
+ if (!fs.existsSync(binaryPath)) {
88
+ throw new Error(`[codegenie] Binary file missing from ${packageName}: ${binaryPath}`)
89
+ }
90
+
91
+ ensureExecutable(binaryPath)
92
+
93
+ return {
94
+ packageName,
95
+ binaryPath,
96
+ platformDir,
97
+ }
98
+ }
99
+
100
+ module.exports = {
101
+ detectLibc,
102
+ resolveBinary,
103
+ resolvePlatformPackageDir,
104
+ resolvePackageName,
105
+ }
106
+
107
+
@@ -0,0 +1,31 @@
1
+ const NON_INTERACTIVE_ARGS = new Set([
2
+ "--version", "-v", "--help", "-h",
3
+ "check-update", "upgrade", "rollback", "uninstall",
4
+ "login", "logout",
5
+ ])
6
+
7
+ function isInteractiveLaunch(argv = []) {
8
+ if (argv.length === 0) return true
9
+ if (argv[0] === "run" || argv[0] === "--") return true
10
+ return false
11
+ }
12
+
13
+ function shouldPrintStartupHint(argv = [], options = {}) {
14
+ const env = options.env || process.env
15
+ const isTTY = options.isTTY ?? process.stderr.isTTY
16
+
17
+ if (!isTTY) return false
18
+ if (env.CODEGENIE_PREPARE_ONLY === "true" || env.CODEGENIE_WARM_STARTUP === "true") return false
19
+ if (argv.length > 0 && NON_INTERACTIVE_ARGS.has(argv[0])) return false
20
+ return isInteractiveLaunch(argv)
21
+ }
22
+
23
+ function startupHintText() {
24
+ return "\x1b[36m\x1b[1m CodeGenie\x1b[0m\x1b[2m Loading...\x1b[0m"
25
+ }
26
+
27
+ module.exports = {
28
+ isInteractiveLaunch,
29
+ shouldPrintStartupHint,
30
+ startupHintText,
31
+ }
package/package.json CHANGED
@@ -1,14 +1,38 @@
1
1
  {
2
2
  "name": "@anieo/codegenie-cli",
3
- "bin": {
4
- "codegenie": "./bin/codegenie"
5
- },
3
+ "version": "0.0.0-develop-202604072034",
4
+ "private": false,
5
+ "description": "HarmonyOS AI 开发 CLI,通过 npm 分发平台二进制",
6
+ "license": "MIT",
6
7
  "scripts": {
7
- "postinstall": "bun ./postinstall.mjs || node ./postinstall.mjs"
8
+ "postinstall": "node ./bin/postinstall.js",
9
+ "preuninstall": "node ./bin/uninstall.js",
10
+ "uninstall": "node ./bin/uninstall.js",
11
+ "postuninstall": "node ./bin/uninstall.js"
8
12
  },
9
- "version": "0.0.0-develop-202604071142",
10
- "license": "MIT",
13
+ "bin": {
14
+ "codegenie": "bin/codegenie.js"
15
+ },
16
+ "files": [
17
+ "bin",
18
+ "lib",
19
+ "README.md",
20
+ "platform-map.json"
21
+ ],
22
+ "keywords": [
23
+ "cli",
24
+ "harmonyos",
25
+ "codegenie",
26
+ "ai"
27
+ ],
11
28
  "optionalDependencies": {
12
- "codegenie-darwin-arm64": "0.0.0-develop-202604071142"
29
+ "@anieo/codegenie-cli-darwin-arm64": "0.0.0-develop-202604072034"
30
+ },
31
+ "publishConfig": {
32
+ "access": "public"
33
+ },
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "https://gitcode.com/codegenie/codegenie.git"
13
37
  }
14
38
  }
@@ -0,0 +1,3 @@
1
+ {
2
+ "darwin-arm64": "@anieo/codegenie-cli-darwin-arm64"
3
+ }
package/bin/codegenie DELETED
@@ -1,179 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- const childProcess = require("child_process")
4
- const fs = require("fs")
5
- const path = require("path")
6
- const os = require("os")
7
-
8
- function run(target) {
9
- const result = childProcess.spawnSync(target, process.argv.slice(2), {
10
- stdio: "inherit",
11
- })
12
- if (result.error) {
13
- console.error(result.error.message)
14
- process.exit(1)
15
- }
16
- const code = typeof result.status === "number" ? result.status : 0
17
- process.exit(code)
18
- }
19
-
20
- const envPath = process.env.CODEGENIE_BIN_PATH
21
- if (envPath) {
22
- run(envPath)
23
- }
24
-
25
- const scriptPath = fs.realpathSync(__filename)
26
- const scriptDir = path.dirname(scriptPath)
27
-
28
- //
29
- const cached = path.join(scriptDir, ".codegenie")
30
- if (fs.existsSync(cached)) {
31
- run(cached)
32
- }
33
-
34
- const platformMap = {
35
- darwin: "darwin",
36
- linux: "linux",
37
- win32: "windows",
38
- }
39
- const archMap = {
40
- x64: "x64",
41
- arm64: "arm64",
42
- arm: "arm",
43
- }
44
-
45
- let platform = platformMap[os.platform()]
46
- if (!platform) {
47
- platform = os.platform()
48
- }
49
- let arch = archMap[os.arch()]
50
- if (!arch) {
51
- arch = os.arch()
52
- }
53
- const base = "codegenie-" + platform + "-" + arch
54
- const binary = platform === "windows" ? "codegenie.exe" : "codegenie"
55
-
56
- function supportsAvx2() {
57
- if (arch !== "x64") return false
58
-
59
- if (platform === "linux") {
60
- try {
61
- return /(^|\s)avx2(\s|$)/i.test(fs.readFileSync("/proc/cpuinfo", "utf8"))
62
- } catch {
63
- return false
64
- }
65
- }
66
-
67
- if (platform === "darwin") {
68
- try {
69
- const result = childProcess.spawnSync("sysctl", ["-n", "hw.optional.avx2_0"], {
70
- encoding: "utf8",
71
- timeout: 1500,
72
- })
73
- if (result.status !== 0) return false
74
- return (result.stdout || "").trim() === "1"
75
- } catch {
76
- return false
77
- }
78
- }
79
-
80
- if (platform === "windows") {
81
- const cmd =
82
- '(Add-Type -MemberDefinition "[DllImport(""kernel32.dll"")] public static extern bool IsProcessorFeaturePresent(int ProcessorFeature);" -Name Kernel32 -Namespace Win32 -PassThru)::IsProcessorFeaturePresent(40)'
83
-
84
- for (const exe of ["powershell.exe", "pwsh.exe", "pwsh", "powershell"]) {
85
- try {
86
- const result = childProcess.spawnSync(exe, ["-NoProfile", "-NonInteractive", "-Command", cmd], {
87
- encoding: "utf8",
88
- timeout: 3000,
89
- windowsHide: true,
90
- })
91
- if (result.status !== 0) continue
92
- const out = (result.stdout || "").trim().toLowerCase()
93
- if (out === "true" || out === "1") return true
94
- if (out === "false" || out === "0") return false
95
- } catch {
96
- continue
97
- }
98
- }
99
-
100
- return false
101
- }
102
-
103
- return false
104
- }
105
-
106
- const names = (() => {
107
- const avx2 = supportsAvx2()
108
- const baseline = arch === "x64" && !avx2
109
-
110
- if (platform === "linux") {
111
- const musl = (() => {
112
- try {
113
- if (fs.existsSync("/etc/alpine-release")) return true
114
- } catch {
115
- // ignore
116
- }
117
-
118
- try {
119
- const result = childProcess.spawnSync("ldd", ["--version"], { encoding: "utf8" })
120
- const text = ((result.stdout || "") + (result.stderr || "")).toLowerCase()
121
- if (text.includes("musl")) return true
122
- } catch {
123
- // ignore
124
- }
125
-
126
- return false
127
- })()
128
-
129
- if (musl) {
130
- if (arch === "x64") {
131
- if (baseline) return [`${base}-baseline-musl`, `${base}-musl`, `${base}-baseline`, base]
132
- return [`${base}-musl`, `${base}-baseline-musl`, base, `${base}-baseline`]
133
- }
134
- return [`${base}-musl`, base]
135
- }
136
-
137
- if (arch === "x64") {
138
- if (baseline) return [`${base}-baseline`, base, `${base}-baseline-musl`, `${base}-musl`]
139
- return [base, `${base}-baseline`, `${base}-musl`, `${base}-baseline-musl`]
140
- }
141
- return [base, `${base}-musl`]
142
- }
143
-
144
- if (arch === "x64") {
145
- if (baseline) return [`${base}-baseline`, base]
146
- return [base, `${base}-baseline`]
147
- }
148
- return [base]
149
- })()
150
-
151
- function findBinary(startDir) {
152
- let current = startDir
153
- for (;;) {
154
- const modules = path.join(current, "node_modules")
155
- if (fs.existsSync(modules)) {
156
- for (const name of names) {
157
- const candidate = path.join(modules, name, "bin", binary)
158
- if (fs.existsSync(candidate)) return candidate
159
- }
160
- }
161
- const parent = path.dirname(current)
162
- if (parent === current) {
163
- return
164
- }
165
- current = parent
166
- }
167
- }
168
-
169
- const resolved = findBinary(scriptDir)
170
- if (!resolved) {
171
- console.error(
172
- "It seems that your package manager failed to install the right version of the codegenie CLI for your platform. You can try manually installing " +
173
- names.map((n) => `\"${n}\"`).join(" or ") +
174
- " package",
175
- )
176
- process.exit(1)
177
- }
178
-
179
- run(resolved)
package/postinstall.mjs DELETED
@@ -1,131 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import fs from "fs"
4
- import path from "path"
5
- import os from "os"
6
- import { fileURLToPath } from "url"
7
- import { createRequire } from "module"
8
-
9
- const __dirname = path.dirname(fileURLToPath(import.meta.url))
10
- const require = createRequire(import.meta.url)
11
-
12
- function detectPlatformAndArch() {
13
- // Map platform names
14
- let platform
15
- switch (os.platform()) {
16
- case "darwin":
17
- platform = "darwin"
18
- break
19
- case "linux":
20
- platform = "linux"
21
- break
22
- case "win32":
23
- platform = "windows"
24
- break
25
- default:
26
- platform = os.platform()
27
- break
28
- }
29
-
30
- // Map architecture names
31
- let arch
32
- switch (os.arch()) {
33
- case "x64":
34
- arch = "x64"
35
- break
36
- case "arm64":
37
- arch = "arm64"
38
- break
39
- case "arm":
40
- arch = "arm"
41
- break
42
- default:
43
- arch = os.arch()
44
- break
45
- }
46
-
47
- return { platform, arch }
48
- }
49
-
50
- function findBinary() {
51
- const { platform, arch } = detectPlatformAndArch()
52
- const packageName = `codegenie-${platform}-${arch}`
53
- const binaryName = platform === "windows" ? "codegenie.exe" : "codegenie"
54
-
55
- try {
56
- // Use require.resolve to find the package
57
- const packageJsonPath = require.resolve(`${packageName}/package.json`)
58
- const packageDir = path.dirname(packageJsonPath)
59
- const binaryPath = path.join(packageDir, "bin", binaryName)
60
-
61
- if (!fs.existsSync(binaryPath)) {
62
- throw new Error(`Binary not found at ${binaryPath}`)
63
- }
64
-
65
- return { binaryPath, binaryName }
66
- } catch (error) {
67
- throw new Error(`Could not find package ${packageName}: ${error.message}`)
68
- }
69
- }
70
-
71
- function prepareBinDirectory(binaryName) {
72
- const binDir = path.join(__dirname, "bin")
73
- const targetPath = path.join(binDir, binaryName)
74
-
75
- // Ensure bin directory exists
76
- if (!fs.existsSync(binDir)) {
77
- fs.mkdirSync(binDir, { recursive: true })
78
- }
79
-
80
- // Remove existing binary/symlink if it exists
81
- if (fs.existsSync(targetPath)) {
82
- fs.unlinkSync(targetPath)
83
- }
84
-
85
- return { binDir, targetPath }
86
- }
87
-
88
- function symlinkBinary(sourcePath, binaryName) {
89
- const { targetPath } = prepareBinDirectory(binaryName)
90
-
91
- fs.symlinkSync(sourcePath, targetPath)
92
- console.log(`codegenie binary symlinked: ${targetPath} -> ${sourcePath}`)
93
-
94
- // Verify the file exists after operation
95
- if (!fs.existsSync(targetPath)) {
96
- throw new Error(`Failed to symlink binary to ${targetPath}`)
97
- }
98
- }
99
-
100
- async function main() {
101
- try {
102
- if (os.platform() === "win32") {
103
- // On Windows, the .exe is already included in the package and bin field points to it
104
- // No postinstall setup needed
105
- console.log("Windows detected: binary setup not needed (using packaged .exe)")
106
- return
107
- }
108
-
109
- // On non-Windows platforms, just verify the binary package exists
110
- // Don't replace the wrapper script - it handles binary execution
111
- const { binaryPath } = findBinary()
112
- const target = path.join(__dirname, "bin", ".codegenie")
113
- if (fs.existsSync(target)) fs.unlinkSync(target)
114
- try {
115
- fs.linkSync(binaryPath, target)
116
- } catch {
117
- fs.copyFileSync(binaryPath, target)
118
- }
119
- fs.chmodSync(target, 0o755)
120
- } catch (error) {
121
- console.error("Failed to setup codegenie binary:", error.message)
122
- process.exit(1)
123
- }
124
- }
125
-
126
- try {
127
- main()
128
- } catch (error) {
129
- console.error("Postinstall script error:", error.message)
130
- process.exit(0)
131
- }