@andyqiu/codeforge 0.3.13 → 0.3.14

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@andyqiu/codeforge",
3
- "version": "0.3.13",
3
+ "version": "0.3.14",
4
4
  "description": "CodeForge — opencode 的零侵入扩展包",
5
5
  "type": "module",
6
6
  "private": false,
@@ -27,6 +27,7 @@
27
27
  "access": "public"
28
28
  },
29
29
  "scripts": {
30
+ "postinstall": "node ./scripts/postinstall.mjs",
30
31
  "prebuild": "node ./scripts/check-bun.mjs",
31
32
  "build": "node ./scripts/build-with-version.mjs",
32
33
  "build:types": "tsc -p tsconfig.build.json --emitDeclarationOnly",
@@ -123,6 +124,7 @@
123
124
  "scripts/check-bun.mjs",
124
125
  "scripts/merge-agents-md.mjs",
125
126
  "scripts/sync-agent-models.mjs",
127
+ "scripts/postinstall.mjs",
126
128
  "schemas/",
127
129
  "install.sh",
128
130
  "install.ps1",
@@ -0,0 +1,125 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * scripts/postinstall.mjs — npm postinstall 自动全局安装入口
4
+ *
5
+ * 设计意图(ADR: npm-postinstall-auto-global):
6
+ * - npm install -g @andyqiu/codeforge 完成后自动等效 `codeforge install --global`
7
+ * - 本地 install / devDep install / pnpm·yarn·bun 全局安装 → fail-closed 不触发
8
+ * - 任何失败均 exit 0,绝不阻断包管理器主流程
9
+ *
10
+ * 包管理器矩阵(详见 ADR Decision 段):
11
+ * npm -g ✅ 唯一保证注入 npm_config_global=true 的包管理器 → 触发安装
12
+ * pnpm ❌ v11+ 官方声明不传递 npm_config_*;fail-closed + stderr 提示
13
+ * yarn ❌ classic/berry 均不传递 npm_config_*;fail-closed + stderr 提示
14
+ * bun ❌ 行为未文档化;fail-closed + stderr 提示
15
+ * unknown ❌ 无 user_agent 信号;静默 exit 0
16
+ *
17
+ * 短路条件(任一命中即静默 exit 0):
18
+ * - CODEFORGE_SKIP_POSTINSTALL=1 用户/CI 显式禁用
19
+ * - CI=true 且未设 CODEFORGE_POSTINSTALL_IN_CI=1 避免污染 CI ~/.config
20
+ * - 未支持的 process.platform(仅 linux/darwin/win32 通过)
21
+ */
22
+
23
+ import { spawnSync } from "node:child_process"
24
+ import * as path from "node:path"
25
+ import * as url from "node:url"
26
+
27
+ const __filename = url.fileURLToPath(import.meta.url)
28
+ const __dirname = path.dirname(__filename)
29
+ const REPO_ROOT = path.resolve(__dirname, "..")
30
+
31
+ // ────────────────────────────────────────────────────────────────────
32
+ // 工具函数
33
+ // ────────────────────────────────────────────────────────────────────
34
+
35
+ /**
36
+ * 解析 npm_config_user_agent,识别包管理器。
37
+ * 所有主流包管理器都设此变量,格式形如:
38
+ * "npm/10.0.0 node/v20.0.0 linux x64 workspaces/false"
39
+ * "pnpm/9.0.0 npm/? node/v20.0.0 linux x64"
40
+ * "yarn/1.22.0 npm/? node/v18.0.0 linux x64"
41
+ * "bun/1.0.0 npm/? node/v20.0.0 linux x64"
42
+ */
43
+ function detectPackageManager() {
44
+ const ua = process.env.npm_config_user_agent || ""
45
+ if (ua.startsWith("npm/")) return "npm"
46
+ if (ua.startsWith("pnpm/")) return "pnpm"
47
+ if (ua.startsWith("yarn/")) return "yarn"
48
+ if (ua.startsWith("bun/")) return "bun"
49
+ return "unknown"
50
+ }
51
+
52
+ function warn(msg) {
53
+ // 写 stderr 避免污染期望干净 stdout 的脚本
54
+ process.stderr.write(`[codeforge postinstall] ${msg}\n`)
55
+ }
56
+
57
+ function exitOk(reason) {
58
+ // 调试/测试可读:CODEFORGE_POSTINSTALL_DEBUG=1 时打印短路原因到 stderr
59
+ if (process.env.CODEFORGE_POSTINSTALL_DEBUG === "1") {
60
+ process.stderr.write(`[codeforge postinstall] skip: ${reason}\n`)
61
+ }
62
+ process.exit(0)
63
+ }
64
+
65
+ // ────────────────────────────────────────────────────────────────────
66
+ // 主流程(全局 try/catch 兜底,任何异常 → exit 0)
67
+ // ────────────────────────────────────────────────────────────────────
68
+
69
+ try {
70
+ // ── 短路 S1: 用户/CI 显式禁用 ──
71
+ if (process.env.CODEFORGE_SKIP_POSTINSTALL === "1") {
72
+ exitOk("CODEFORGE_SKIP_POSTINSTALL=1")
73
+ }
74
+
75
+ // ── 短路 S2: CI 环境默认跳过 ──
76
+ if (process.env.CI === "true" && process.env.CODEFORGE_POSTINSTALL_IN_CI !== "1") {
77
+ exitOk("CI=true (set CODEFORGE_POSTINSTALL_IN_CI=1 to opt in)")
78
+ }
79
+
80
+ // ── 短路 S3: 未支持平台 ──
81
+ const supportedPlatforms = ["linux", "darwin", "win32"]
82
+ if (!supportedPlatforms.includes(process.platform)) {
83
+ exitOk(`unsupported platform: ${process.platform}`)
84
+ }
85
+
86
+ // ── 主决策 ──
87
+ const pm = detectPackageManager()
88
+ const isGlobal = process.env.npm_config_global === "true"
89
+
90
+ // D1: npm + global → 触发安装
91
+ if (pm === "npm" && isGlobal) {
92
+ const cli = path.join(REPO_ROOT, "bin", "codeforge.mjs")
93
+ const args = [cli, "install", "--global", "--skip-build"]
94
+ const env = { ...process.env, CODEFORGE_FROM_POSTINSTALL: "1" }
95
+ const r = spawnSync(process.execPath, args, {
96
+ stdio: "inherit",
97
+ env,
98
+ })
99
+ if (r.status !== 0) {
100
+ warn(
101
+ `自动全局安装失败(exit code ${r.status ?? "unknown"})。` +
102
+ `请手动执行:codeforge install --global`,
103
+ )
104
+ }
105
+ // 无论成功失败,都 exit 0,不阻断 npm
106
+ process.exit(0)
107
+ }
108
+
109
+ // D2: 识别为 pnpm/yarn/bun → fail-closed + 用户可见提示
110
+ if (pm === "pnpm" || pm === "yarn" || pm === "bun") {
111
+ warn(
112
+ `检测到使用 ${pm},无法自动确定是否为全局安装;` +
113
+ `如果你刚才跑的是 \`${pm} global add\` / \`add -g\`,` +
114
+ `请手动执行:codeforge install --global`,
115
+ )
116
+ process.exit(0)
117
+ }
118
+
119
+ // D3: 其它(npm 但非 global / unknown pm / 无 user_agent)→ 静默 exit 0
120
+ exitOk(`no-op (pm=${pm}, global=${isGlobal})`)
121
+ } catch (e) {
122
+ // 任何未捕获异常都不向 npm 抛错
123
+ warn(`unexpected error: ${e && e.message ? e.message : String(e)}`)
124
+ process.exit(0)
125
+ }
@@ -100,9 +100,16 @@ weighted_score = 0.8×0.30 + 0.5×0.25 + 0.3×0.20 + 0.6×0.15 + 0.2×0.10
100
100
 
101
101
  **Functional 常见打分依据**:
102
102
  - 0.0:只说了"做个东西",完全不知道做什么
103
+ - 0.2:有隐约方向但目标群体/核心输出不明(如"做个管理工具")
104
+ - 0.4:目标群体 + 核心使用场景已清晰,但核心功能边界还未明确(如"给老板看指标的看板",知道谁用/做什么,但不知道哪些指标/什么展示形式)
103
105
  - 0.5:知道大方向("做个导出"),但不知道输出形式、流程
104
106
  - 1.0:输入输出明确,核心流程可描述,用户能说出 Job
105
107
 
108
+ > **初轮信息密度校准**(方案 A 补充):Phase A 初轮评分反映的是**信息密度**,不是需求质量高低。
109
+ > 用户首轮说出「目标群体 + 核心 Job」即可给 0.4,不要因为细节不足降到 0.2。
110
+ > 0.2 应保留给真正「只有一个动词、连做什么都不清楚」的极端情形。
111
+ > 典型校准案例:「做看板让老板看指标」= 目标群体(老板)+ 核心输出(看板/指标)已给出 → Functional ≥ 0.4。
112
+
106
113
  **Edge Cases 常见打分依据**:
107
114
  - 0.0:完全没讨论过边界
108
115
  - 0.5:讨论了 1-2 个正常 happy path,无异常路径