@double-codeing/flow2spec 3.1.1 → 3.1.2

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.en.md CHANGED
@@ -151,7 +151,7 @@ natural language: implement the proposal above ← AI starts coding (tas
151
151
  | `/f2s-kb-feat` | Add a new capability |
152
152
  | `/f2s-kb-fix` | Fix a bug |
153
153
  | `/f2s-kb-sync` | Sync knowledge base |
154
- | `/f2s-git-commit` | Commit code |
154
+ | `/f2s-git-commit` | Commit code; "quick commit" skips KB coverage check |
155
155
  | `/f2s-kb-add <path>` | Import API module into knowledge base |
156
156
 
157
157
  For the full command list, see [Usage Guide](./docs/en/usage-guide.md) · [Commands Reference](./docs/en/commands-reference.md)
@@ -186,4 +186,4 @@ For the full command list, see [Usage Guide](./docs/en/usage-guide.md) · [Comma
186
186
 
187
187
  ## License
188
188
 
189
- MIT. Copyright © 2026 兰涛
189
+ MIT. Copyright © 2026 兰涛
@@ -65,6 +65,10 @@ Type meanings:
65
65
  | `config` | Configuration items, switches, defaults, initialization parameters |
66
66
  | `policy` | Process, rule, constraint, gate, prohibition, agent orchestration, skill step |
67
67
 
68
+ ## Topic Granularity
69
+
70
+ A topic is a routing summary plus key boundaries; details belong in `stock-docs/`. Consider splitting into a main topic plus independently matchable sub-topics when its stock-doc exceeds 300-500 lines, matcher `includeAny` exceeds 12 terms, or the body spans more than 3 unrelated responsibility areas.
71
+
68
72
  ---
69
73
 
70
74
  ## Related Documents
@@ -116,6 +116,8 @@ After `flow2spec init codex`, Codex projects include `.codex/hooks.json` and `.c
116
116
 
117
117
  After `flow2spec init cursor`, Cursor projects include `.cursor/hooks.json` and `.cursor/hooks/f2s-update-check.js`. The hook runs on Cursor `sessionStart` and injects upgrade reminders through `additional_context`. Set `updateCheck.enabled=false` in `flow2spec.config.json` to skip the check.
118
118
 
119
+ After `flow2spec init claude`, Claude projects include `.claude/settings.json` and `.claude/hooks/f2s-update-check.js`. All three integrations now use a single SessionStart hook. The script injects an agent-instruction notice through `additional_context`, requiring the agent to relay the message verbatim to the user. The notice format is: "Current project `<project>` knowledge-base version v<current>, lower than latest package version v<latest>. Run the f2s-kb-upgrade skill to align templates and routing." If today's cache still flags a needed upgrade, every new session re-injects the reminder; after a successful upgrade, `f2s-kb-upgrade` clears `.Knowledge/update-check.json` so stale reminders disappear.
120
+
119
121
  ---
120
122
 
121
123
  ## 4. Agent Execution Configuration
@@ -120,6 +120,8 @@ Codex 项目执行 `flow2spec init codex` 后会写入 `.codex/hooks.json` 与 `
120
120
 
121
121
  Cursor 项目执行 `flow2spec init cursor` 后会写入 `.cursor/hooks.json` 与 `.cursor/hooks/f2s-update-check.js`,在 Cursor `sessionStart` 自动检查知识库版本;脚本通过 `additional_context` 把升级提示注入会话。`flow2spec.config.json` 中 `updateCheck.enabled=false` 时跳过检查。
122
122
 
123
+ Claude 项目执行 `flow2spec init claude` 后会写入 `.claude/settings.json` 与 `.claude/hooks/f2s-update-check.js`,在 Claude `SessionStart` 自动检查知识库版本——三端均为单脚本架构。脚本通过 `additional_context` 注入命令式升级提示(agent-instruction 文案要求 agent 必须原文转告用户),格式为:"当前项目「<项目名>」知识库版本 v<当前版本>,低于最新包版本 v<最新版本>。可执行 f2s-kb-upgrade skill 对齐模板与路由。"若当天缓存仍标记需升级,新会话每次都会重新注入提示;升级成功后 `f2s-kb-upgrade` 会清理 `.Knowledge/update-check.json`,避免旧提示残留。
124
+
123
125
  ---
124
126
 
125
127
  ## 四、Agent 执行配置
@@ -65,6 +65,10 @@ Memory Coding 四环总览见 [体系与原理 §1](./体系与原理.md)。
65
65
  | `config` | 配置项、开关、默认值、初始化参数 |
66
66
  | `policy` | 流程、规则、约束、门禁、禁止项、agent 编排、技能步骤 |
67
67
 
68
+ ## 主题粒度
69
+
70
+ topic 是路由摘要与关键边界,细节放在 `stock-docs/`。若对应 stock-doc 超过 300–500 行、matcher `includeAny` 超过 12 个,或正文出现 3 个以上不相干职责域,建议拆成主 topic + 可独立命中的子 topic。
71
+
68
72
  ---
69
73
 
70
74
  ## 相关文档
@@ -191,7 +191,9 @@ flowchart LR
191
191
  J -- 是 --> Z
192
192
  J -- 否 --> K{.Knowledge/update-check.json 今天已检查?}
193
193
 
194
- K -- 是 --> Z
194
+ K -- 是 --> K1{缓存显示需升级?}
195
+ K1 -- 否 --> Z
196
+ K1 -- 是 --> Q
195
197
  K -- 否 --> L[读取 .Knowledge/manifest-routing.json version]
196
198
 
197
199
  L --> M{有 manifest version?}
@@ -26,6 +26,22 @@ function hasHookCommand(arr, fragment) {
26
26
  return false;
27
27
  }
28
28
 
29
+ function removeHookCommand(arr, fragment) {
30
+ if (!Array.isArray(arr)) return [];
31
+ const next = [];
32
+ for (const group of arr) {
33
+ if (!group || !Array.isArray(group.hooks)) {
34
+ next.push(group);
35
+ continue;
36
+ }
37
+ const hooks = group.hooks.filter((h) => {
38
+ return !(h && h.type === 'command' && String(h.command || '').includes(fragment));
39
+ });
40
+ if (hooks.length) next.push(Object.assign({}, group, { hooks }));
41
+ }
42
+ return next;
43
+ }
44
+
29
45
  // 旧函数名保持兼容
30
46
  function hasF2sHook(preToolUseArr) {
31
47
  return hasHookCommand(preToolUseArr, 'f2s-config-inject');
@@ -75,7 +91,9 @@ function mergeConfigSessionHook(existing) {
75
91
  }
76
92
 
77
93
  /**
78
- * 将 f2s SessionStart(版本检查)hook 合并进 settings
94
+ * 将 f2s 更新检查 hook 合并进 settings
95
+ * - SessionStart:执行完整检测,写入 .Knowledge/update-check.json,并直接 emit 提示
96
+ * - 同时清理旧版 UserPromptSubmit 中的 f2s-update-check / f2s-update-notice
79
97
  * @param {object} existing
80
98
  * @returns {{ settings, changed }}
81
99
  */
@@ -84,15 +102,26 @@ function mergeUpdateCheckHook(existing) {
84
102
  if (!next.hooks) next.hooks = {};
85
103
  if (!next.hooks.SessionStart) next.hooks.SessionStart = [];
86
104
 
87
- if (hasHookCommand(next.hooks.SessionStart, 'f2s-update-check')) {
88
- return { settings: next, changed: false };
105
+ let changed = false;
106
+
107
+ if (Array.isArray(next.hooks.UserPromptSubmit)) {
108
+ const before = JSON.stringify(next.hooks.UserPromptSubmit);
109
+ next.hooks.UserPromptSubmit = removeHookCommand(next.hooks.UserPromptSubmit, 'f2s-update-check');
110
+ next.hooks.UserPromptSubmit = removeHookCommand(next.hooks.UserPromptSubmit, 'f2s-update-notice');
111
+ if (JSON.stringify(next.hooks.UserPromptSubmit) !== before) changed = true;
112
+ if (next.hooks.UserPromptSubmit.length === 0) {
113
+ delete next.hooks.UserPromptSubmit;
114
+ }
89
115
  }
90
116
 
91
- next.hooks.SessionStart.push({
92
- hooks: [{ type: 'command', command: HOOK_COMMAND_UPDATE_CHECK }],
93
- });
117
+ if (!hasHookCommand(next.hooks.SessionStart, 'f2s-update-check')) {
118
+ next.hooks.SessionStart.push({
119
+ hooks: [{ type: 'command', command: HOOK_COMMAND_UPDATE_CHECK }],
120
+ });
121
+ changed = true;
122
+ }
94
123
 
95
- return { settings: next, changed: true };
124
+ return { settings: next, changed };
96
125
  }
97
126
 
98
127
  /**
@@ -145,7 +174,7 @@ function copyHookScript(claudeRoot, templatesDir, scriptName) {
145
174
  }
146
175
 
147
176
  /**
148
- * 主入口:为 claude agent 配置 f2s hooks(SessionStart 配置摘要 + PreToolUse 守门 + SessionStart 更新检查)。
177
+ * 主入口:为 claude agent 配置 f2s hooks(SessionStart 配置摘要 + PreToolUse 守门 + 更新检测/提示)。
149
178
  * @param {string} cwd
150
179
  * @param {string} templatesDir
151
180
  * @returns {{ hookScriptResult, updateCheckResult, settingsChanged }}
@@ -158,6 +187,12 @@ function writeClaudeAgentHooks(cwd, templatesDir) {
158
187
  const configSessionResult = copyHookScript(claudeRoot, templatesDir, 'f2s-config-session.js');
159
188
  const updateCheckResult = copyHookScript(claudeRoot, templatesDir, 'f2s-update-check.js');
160
189
 
190
+ // 清理旧版残留的 f2s-update-notice.js
191
+ const noticeStale = path.join(claudeRoot, 'hooks', 'f2s-update-notice.js');
192
+ if (fs.existsSync(noticeStale)) {
193
+ try { fs.unlinkSync(noticeStale); } catch (_) {}
194
+ }
195
+
161
196
  let settings = readSettings(claudeRoot);
162
197
  let changed = false;
163
198
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@double-codeing/flow2spec",
3
- "version": "3.1.1",
3
+ "version": "3.1.2",
4
4
  "description": "在业务仓库初始化「文档驱动、可写回知识库」的 AI 协作骨架:项目根 .Knowledge 承载 stock-docs/req-docs 与机读路由,.cursor/.claude/.codex 写入 f2s-* 规则与技能(含 Karpathy 式编码行为准则,init 同步 rules / Codex topics / skills);init 只落结构与模板,业务内容由各 f2s-* 技能在对话中维护。",
5
5
  "homepage": "https://github.com/Lands-1203/Flow2Spec#readme",
6
6
  "repository": {
@@ -100,7 +100,7 @@ Codex 由 `flow2spec init codex` 写入 **`.codex/hooks.json`**,在 `SessionSt
100
100
  **规则层双保险**(若 hook 未运行,则按本节补检;与脚本缓存互为备份):
101
101
 
102
102
  1. 读 `flow2spec.config.json` → 若 `updateCheck.enabled` 不为 `true`,跳过,不做任何提示。
103
- 2. 读 `.Knowledge/update-check.json` → 若文件存在且 `checkedAt` 与今日为同一自然日(`new Date(checkedAt).toDateString() === new Date().toDateString()`),**跳过,不执行脚本,不做任何提示**。
103
+ 2. 读 `.Knowledge/update-check.json` → 若文件存在且 `checkedAt` 与今日为同一自然日(`new Date(checkedAt).toDateString() === new Date().toDateString()`),不重复查 npm;但若 `needsUpgrade=true` 或 `latestNpm > manifestVersion`,本会话首次回复用户时仍须提醒执行 `f2s-kb-upgrade`;若当前 `.Knowledge/manifest-routing.json.version` 已不低于 `latestNpm`,删除该缓存并不再提示。
104
104
  3. 上述两步均未跳过时:执行 `node .codex/hooks/f2s-update-check.js`,解析标准输出的 JSON:
105
105
  - 若含 `hookSpecificOutput.additionalContext`:**告知用户**该内容(建议执行 `/f2s-kb-upgrade`)。
106
106
  - 无输出或解析失败:静默,不提示。
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  'use strict';
3
3
  /**
4
- * flow2spec UserPromptSubmit hook — 每天第一次对话时检查版本更新。
4
+ * flow2spec SessionStart hook — 每天第一次对话时检查版本更新。
5
5
  * 比较本地知识库 manifest-routing.json 的 version 与 npm 最新版本:
6
6
  * - 一致或本地更新 → 静默退出
7
7
  * - 落后 → 向 Agent 上下文注入一行提示(建议执行 f2s-kb-upgrade)
8
- * 已检查过(24h 内)则完全静默,不做任何输出。
8
+ * 已检查过且无需升级则静默;已检查且仍需升级时,每个新会话继续注入提醒。
9
9
  * 由 flow2spec init 写入对应 agent 的 hooks/f2s-update-check.js。
10
10
  */
11
11
  const fs = require('fs');
@@ -32,16 +32,58 @@ function readCache() {
32
32
  } catch (_) { return null; }
33
33
  }
34
34
 
35
+ function getProjectName() {
36
+ try {
37
+ const pkg = JSON.parse(fs.readFileSync(path.join(process.cwd(), 'package.json'), 'utf8'));
38
+ if (pkg && pkg.name) return String(pkg.name);
39
+ } catch (_) {}
40
+ return path.basename(process.cwd());
41
+ }
42
+
43
+ function buildNotice(latestNpm, manifestVersion) {
44
+ const userMsg = `📦 [flow2spec] 当前项目「${getProjectName()}」知识库版本 v${manifestVersion},低于最新包版本 v${latestNpm}。可执行 f2s-kb-upgrade skill 对齐模板与路由。`;
45
+ return [
46
+ `[flow2spec/agent-instruction] 你必须在本轮回复开头将下列升级提示原文转告用户,不得省略、不得仅在内部判断后跳过:`,
47
+ ``,
48
+ userMsg,
49
+ ].join('\n');
50
+ }
51
+
52
+ function emitNotice(notice) {
53
+ process.stdout.write(
54
+ JSON.stringify({
55
+ additional_context: notice,
56
+ hookSpecificOutput: {
57
+ hookEventName: 'SessionStart',
58
+ additionalContext: notice,
59
+ },
60
+ }) + '\n'
61
+ );
62
+ }
63
+
35
64
  function writeCache(latestNpm, manifestVersion) {
36
65
  try {
66
+ const needsUpgrade = cmpVer(manifestVersion, latestNpm) < 0;
37
67
  fs.writeFileSync(
38
68
  CACHE_FILE,
39
- `${JSON.stringify({ latestNpm, manifestVersion, checkedAt: Date.now() }, null, 2)}\n`,
69
+ `${JSON.stringify({
70
+ latestNpm,
71
+ manifestVersion,
72
+ needsUpgrade,
73
+ notice: needsUpgrade ? buildNotice(latestNpm, manifestVersion) : '',
74
+ checkedAt: Date.now(),
75
+ }, null, 2)}\n`,
40
76
  'utf8'
41
77
  );
42
78
  } catch (_) {}
43
79
  }
44
80
 
81
+ function deleteCache() {
82
+ try {
83
+ if (fs.existsSync(CACHE_FILE)) fs.unlinkSync(CACHE_FILE);
84
+ } catch (_) {}
85
+ }
86
+
45
87
  // ── 版本比较 ─────────────────────────────────────────────────────────────────
46
88
 
47
89
  function parseVer(v) {
@@ -103,7 +145,24 @@ function isEnabled() {
103
145
  function main() {
104
146
  if (process.env.CI || process.env.CONTINUOUS_INTEGRATION) return;
105
147
  if (!isEnabled()) return;
106
- if (readCache()) return; // 今天已检查过,静默退出
148
+ const cache = readCache();
149
+ if (cache) {
150
+ // 今天已检查过则不重复查 npm;若缓存显示仍需升级,每个新会话继续提醒。
151
+ const needsUpgrade = cache.needsUpgrade === true ||
152
+ cmpVer(cache.manifestVersion, cache.latestNpm) < 0;
153
+ if (needsUpgrade) {
154
+ const currentManifestVersion = getManifestVersion();
155
+ if (currentManifestVersion && cache.latestNpm &&
156
+ cmpVer(currentManifestVersion, cache.latestNpm) >= 0) {
157
+ deleteCache();
158
+ return;
159
+ }
160
+ // SessionStart 进入新会话:缓存命中且仍需升级,直接 emit。
161
+ const notice = buildNotice(cache.latestNpm, cache.manifestVersion);
162
+ emitNotice(notice);
163
+ }
164
+ return;
165
+ }
107
166
 
108
167
  const manifestVersion = getManifestVersion();
109
168
  if (!manifestVersion) return; // 无知识库,跳过
@@ -121,21 +180,8 @@ function main() {
121
180
 
122
181
  if (cmpVer(manifestVersion, latestNpm) >= 0) return; // 已是最新
123
182
 
124
- // 知识库落后于 npm 最新版,注入提示
125
- const notice = [
126
- `[flow2spec] 知识库版本 v${manifestVersion} 低于最新包版本 v${latestNpm}。`,
127
- `建议在此对话中执行 f2s-kb-upgrade 升级知识库模板与路由结构。`,
128
- ].join(' ');
129
-
130
- process.stdout.write(
131
- JSON.stringify({
132
- additional_context: notice,
133
- hookSpecificOutput: {
134
- hookEventName: 'SessionStart',
135
- additionalContext: notice,
136
- },
137
- }) + '\n'
138
- );
183
+ const notice = buildNotice(latestNpm, manifestVersion);
184
+ emitNotice(notice);
139
185
  }
140
186
 
141
187
  main();
@@ -89,16 +89,16 @@ alwaysApply: true
89
89
 
90
90
  **例外(应显式否定)**:A、B 两种做法在逻辑上均正确,但项目已做出**排他性选择**时,须写出「不用 B」——不说清楚,读者无法判断 B 是否仍可选。
91
91
 
92
- ## 知识库版本自检(sessionStart 自动触发;每日首次,仅 updateCheck.enabled=true 时)
92
+ ## 知识库版本自检(hook 自动触发;每日首次,仅 updateCheck.enabled=true 时)
93
93
 
94
- Cursor 由 `flow2spec init cursor` 写入 **`.cursor/hooks.json`**,在 `sessionStart` 自动执行 `node .cursor/hooks/f2s-update-check.js`;脚本通过 `additional_context` 把升级提示注入会话。Codex 由 `flow2spec init codex` 写入 **`.codex/hooks.json`**,在 `SessionStart` 的 `startup|resume` 事件自动执行 `node .codex/hooks/f2s-update-check.js`。
94
+ 三端均采用 **SessionStart 单脚本**架构:Cursor 由 `flow2spec init cursor` 写入 **`.cursor/hooks.json`** `sessionStart` 执行 `node .cursor/hooks/f2s-update-check.js`;Codex 由 `flow2spec init codex` 写入 **`.codex/hooks.json`** `SessionStart` 的 `startup|resume` 事件执行 `node .codex/hooks/f2s-update-check.js`;Claude 由 `flow2spec init claude` 写入 **`.claude/settings.json`** 在 `SessionStart` 执行 `node .claude/hooks/f2s-update-check.js`。脚本完成版本比对与缓存写入后,需升级时通过 `additional_context` 注入命令式升级提示(agent-instruction 文案要求 agent 必须原文转告用户)。
95
95
 
96
96
  **规则层双保险**(与脚本缓存互为备份):
97
97
 
98
98
  1. 读 `flow2spec.config.json` → 若 `updateCheck.enabled` 不为 `true`,跳过,不做任何提示。
99
- 2. 读 `.Knowledge/update-check.json` → 若文件存在且 `checkedAt` 与今日为同一自然日(`new Date(checkedAt).toDateString() === new Date().toDateString()`),**跳过,不执行脚本,不做任何提示**。
100
- 3. 上述两步均未跳过时:执行当前 agent 配置根下的更新检测脚本(Cursor:`node .cursor/hooks/f2s-update-check.js`;Codex:`node .codex/hooks/f2s-update-check.js`),解析标准输出的 JSON:
101
- - 若含 `hookSpecificOutput.additionalContext`:**告知用户**该内容(建议执行 `/f2s-kb-upgrade`)。
99
+ 2. 读 `.Knowledge/update-check.json` → 若文件存在且 `checkedAt` 与今日为同一自然日(`new Date(checkedAt).toDateString() === new Date().toDateString()`),不重复查 npm;但若 `needsUpgrade=true` 或 `latestNpm > manifestVersion`,本会话首次回复用户时仍须提醒执行 `f2s-kb-upgrade`;若当前 `.Knowledge/manifest-routing.json.version` 已不低于 `latestNpm`,删除该缓存并不再提示。
100
+ 3. 上述两步均未跳过时:执行当前 agent 配置根下的更新检测脚本(Claude:`node .claude/hooks/f2s-update-check.js`;Cursor:`node .cursor/hooks/f2s-update-check.js`;Codex:`node .codex/hooks/f2s-update-check.js`),解析标准输出的 JSON:
101
+ - 若含 `hookSpecificOutput.additionalContext`:**告知用户**该内容(建议执行 `f2s-kb-upgrade` skill)。
102
102
  - 无输出或解析失败:静默,不提示。
103
103
  4. 以上步骤出现任何错误,静默跳过,不影响正常对话。
104
104
 
@@ -182,6 +182,7 @@ description: 知识库模板升级技能(仅指本 SKILL):**流程分流 V
182
182
  5. 配置根产物是否存在:
183
183
  - Cursor/Claude:`rules/`、`skills/`
184
184
  - Codex:`.codex/AGENTS.md`、`skills/`
185
+ 6. 本技能成功完成后,删除 `.Knowledge/update-check.json`(若存在),让下一次新会话重新检测并清除旧升级提示;若删除失败,在步骤 5 摘要中写明。
185
186
 
186
187
  ### 步骤 5:输出结果摘要(必须)
187
188
 
@@ -195,6 +196,7 @@ description: 知识库模板升级技能(仅指本 SKILL):**流程分流 V
195
196
  - **SKILL 自更新**:`init` 后是否重读 `f2s-kb-upgrade/SKILL.md`;是否因文件变化 **整技能重跑**及轮次(见「init 与技能自更新」)
196
197
  - manifest / matchers 对齐结论(随 init 输出)
197
198
  - 关键文件校验结论
199
+ - `.Knowledge/update-check.json` 清理结论(已删除 / 不存在 / 删除失败)
198
200
  - 如失败,给出下一步可执行修复建议
199
201
 
200
202
  ## 输出摘要模板(建议)
@@ -215,6 +217,7 @@ description: 知识库模板升级技能(仅指本 SKILL):**流程分流 V
215
217
  - manifest-routing / matchers 分片:`已与模板对齐` / `已是最新` / `reset 覆盖`
216
218
  - topics.path:`全部存在` / `存在缺失(见下)`
217
219
  - agent 产物:`通过` / `异常(见下)`
220
+ - update-check 缓存:`已删除` / `不存在` / `删除失败`
218
221
 
219
222
  ### 备注
220
223
  - <失败原因或后续建议>
@@ -239,3 +242,4 @@ description: 知识库模板升级技能(仅指本 SKILL):**流程分流 V
239
242
  8. 是否输出了 manifest 与关键路径校验结果。
240
243
  9. 若失败,是否给出下一步具体命令建议。
241
244
  10. 步骤 3b 的 `index.md` 融合由主 agent 完成并落盘,无子 agent 越权写入。
245
+ 11. 成功升级后是否删除 `.Knowledge/update-check.json`,避免当天新会话继续提示旧升级信息。