agent-step-gate 0.3.0

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.
Files changed (68) hide show
  1. package/ARCHITECTURE.md +393 -0
  2. package/README.md +662 -0
  3. package/SKILL.md +190 -0
  4. package/Weaver.md +140 -0
  5. package/dist/cli.d.ts +1 -0
  6. package/dist/cli.js +573 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/core/errors.d.ts +16 -0
  9. package/dist/core/errors.js +32 -0
  10. package/dist/core/errors.js.map +1 -0
  11. package/dist/core/gate.d.ts +20 -0
  12. package/dist/core/gate.js +82 -0
  13. package/dist/core/gate.js.map +1 -0
  14. package/dist/core/keys.d.ts +18 -0
  15. package/dist/core/keys.js +37 -0
  16. package/dist/core/keys.js.map +1 -0
  17. package/dist/core/plan.d.ts +2 -0
  18. package/dist/core/plan.js +135 -0
  19. package/dist/core/plan.js.map +1 -0
  20. package/dist/core/program.d.ts +69 -0
  21. package/dist/core/program.js +191 -0
  22. package/dist/core/program.js.map +1 -0
  23. package/dist/core/reconcile.d.ts +37 -0
  24. package/dist/core/reconcile.js +198 -0
  25. package/dist/core/reconcile.js.map +1 -0
  26. package/dist/core/session.d.ts +25 -0
  27. package/dist/core/session.js +88 -0
  28. package/dist/core/session.js.map +1 -0
  29. package/dist/index.d.ts +1 -0
  30. package/dist/index.js +29 -0
  31. package/dist/index.js.map +1 -0
  32. package/dist/storage/db.d.ts +3 -0
  33. package/dist/storage/db.js +117 -0
  34. package/dist/storage/db.js.map +1 -0
  35. package/dist/storage/repository.d.ts +24 -0
  36. package/dist/storage/repository.js +449 -0
  37. package/dist/storage/repository.js.map +1 -0
  38. package/dist/tools/activeTask.d.ts +2 -0
  39. package/dist/tools/activeTask.js +41 -0
  40. package/dist/tools/activeTask.js.map +1 -0
  41. package/dist/tools/cancelTask.d.ts +2 -0
  42. package/dist/tools/cancelTask.js +39 -0
  43. package/dist/tools/cancelTask.js.map +1 -0
  44. package/dist/tools/checkpoint.d.ts +2 -0
  45. package/dist/tools/checkpoint.js +71 -0
  46. package/dist/tools/checkpoint.js.map +1 -0
  47. package/dist/tools/current.d.ts +2 -0
  48. package/dist/tools/current.js +64 -0
  49. package/dist/tools/current.js.map +1 -0
  50. package/dist/tools/finalize.d.ts +2 -0
  51. package/dist/tools/finalize.js +95 -0
  52. package/dist/tools/finalize.js.map +1 -0
  53. package/dist/tools/index.d.ts +6 -0
  54. package/dist/tools/index.js +7 -0
  55. package/dist/tools/index.js.map +1 -0
  56. package/dist/tools/startPlan.d.ts +2 -0
  57. package/dist/tools/startPlan.js +124 -0
  58. package/dist/tools/startPlan.js.map +1 -0
  59. package/dist/types/index.d.ts +142 -0
  60. package/dist/types/index.js +6 -0
  61. package/dist/types/index.js.map +1 -0
  62. package/package.json +48 -0
  63. package/scripts/interactive-demo.ts +394 -0
  64. package/scripts/mcp-call.mjs +56 -0
  65. package/scripts/prompt-check-hook.sh +27 -0
  66. package/scripts/session-start-hook.sh +47 -0
  67. package/scripts/stop-hook.mjs +83 -0
  68. package/scripts/stop-hook.sh +75 -0
@@ -0,0 +1,393 @@
1
+ # Agent Step Gate — 完整架构文档
2
+
3
+ **版本**: 0.3.0 | **日期**: 2026-05-30 | **测试**: 116/116
4
+
5
+ ---
6
+
7
+ ## 1. 四层架构
8
+
9
+ ```
10
+ Program (pgm_XXXXXX) ← 跨 Session 大计划
11
+ └─ Node (pg-xxx) ← 一个 Session 的工作单元
12
+ └─ Task (tsk_XXXXXX) ← 一个 DAG 计划
13
+ └─ Step ← 最小执行单元
14
+ ```
15
+
16
+ 每层都有对应的完成凭证:
17
+ ```
18
+ stepKey ──→ taskKey ──→ nodeKey ──→ program (自检)
19
+ (出示) (出示) (收据) (自动)
20
+ ```
21
+
22
+ ### 自底向上传播
23
+
24
+ `finalize` 命令一次调用,自动逐层上浮:
25
+
26
+ ```
27
+ finalize(taskKey)
28
+ → task completed
29
+ → 检查: 同 node 全部 task completed?
30
+ → 是 → 生成 nodeKey → node completed
31
+ → 检查: 同 program 全部 node completed?
32
+ → 是 → program completed
33
+ ```
34
+
35
+ Agent 不需要判断层级——系统自己知道该传播到哪。
36
+
37
+ ---
38
+
39
+ ## 2. 数据库 — 7 张表
40
+
41
+ ### programs
42
+ ```sql
43
+ program_id TEXT PK -- pgm_XXXXXX
44
+ title TEXT
45
+ status TEXT -- active | completed
46
+ total_nodes INTEGER
47
+ created_at / updated_at
48
+ ```
49
+
50
+ ### program_nodes
51
+ ```sql
52
+ node_id TEXT PK -- user-defined or pg_xxx_N
53
+ program_id TEXT FK
54
+ title / description / order_index
55
+ status TEXT -- pending | in_progress | completed
56
+ session_id TEXT
57
+ node_key_hash TEXT -- SHA-256(6-char nodeKey), system-generated
58
+ completed_at / created_at
59
+ ```
60
+
61
+ ### sessions
62
+ ```sql
63
+ session_id TEXT PK -- ses_XXXXXX
64
+ session_secret_hash TEXT -- SHA-256(6-char)
65
+ recovery_token_hash TEXT -- SHA-256(6-char)
66
+ title / workspace
67
+ program_id / program_node_id
68
+ status TEXT -- active | completed | abandoned
69
+ created_by_cli / created_at / updated_at
70
+ ```
71
+
72
+ ### cli_instances
73
+ ```sql
74
+ cli_instance_id TEXT PK -- cli_XXXXXX
75
+ session_id / hostname / pid / workspace
76
+ status TEXT -- active | dead | detached
77
+ created_at / last_seen_at
78
+ ```
79
+
80
+ ### tasks
81
+ ```sql
82
+ id TEXT PK -- tsk_XXXXXX
83
+ title / status -- active | completed | cancelled
84
+ current_index / total_steps
85
+ final_key_hash TEXT -- SHA-256(taskKey)
86
+ session_id TEXT FK
87
+ created_at / updated_at
88
+ ```
89
+
90
+ ### steps
91
+ ```sql
92
+ id TEXT PK -- {taskId}_{nodeId}
93
+ task_id / parent_path / title / path
94
+ order_index / depends_on (JSON)
95
+ status TEXT -- pending | current | completed | skipped
96
+ step_key_hash TEXT -- SHA-256(stepKey), 完成后保留为永久凭证
97
+ completed_at / created_at
98
+ ```
99
+
100
+ ### events
101
+ ```sql
102
+ id / task_id / step_id
103
+ event_type TEXT -- plan_created | step_activated | step_completed
104
+ -- all_steps_completed | task_finalized | task_cancelled
105
+ -- skip_key_consumed
106
+ payload / created_at
107
+ ```
108
+
109
+ ---
110
+
111
+ ## 3. 安全模型 — 5 种凭证
112
+
113
+ | 凭证 | 长度 | 用途 | 生成者 | 验证方式 | 生命周期 |
114
+ |------|------|------|--------|---------|---------|
115
+ | **stepKey** | 6位 | 证明单个 step 完成 | 系统(plan/checkpoint) | SHA-256 hash 匹配 | 一次性,checkpoint 后消耗 |
116
+ | **taskKey** | 6位 | 证明全部 step 完成 | 系统(最后一步 checkpoint) | SHA-256 hash 匹配 | 一次性,finalize 后消耗 |
117
+ | **nodeKey** | 6位 | Node 完成凭证(收据) | 系统(finalize 自动传播) | SHA-256 hash 存 DB | 作为完成凭证返回给 Agent |
118
+ | **sessionSecret** | 6位 | Session 身份认证 | 系统(createSession) | SHA-256 hash 匹配 | Session 生命周期 |
119
+ | **recoveryToken** | 6位 | 崩溃恢复 + 管理操作 | 系统(createSession) | SHA-256 hash 匹配 | Session 生命周期 |
120
+
121
+ ### 隔离规则
122
+ - Task 写操作:session_id 列强制过滤
123
+ - cancel-task:必须同 session,或出示 recoveryToken (--admin)
124
+ - checkpoint 原子性:`WHERE status='current' + affected rows` 防双消费
125
+ - stepKey 一次性:key_hash 保留作永久凭证,但 step 只能 checkpoint 一次
126
+
127
+ ### skipKey 验证 (中断恢复)
128
+ - 旧 task 的 completed step 可作 skipKey 跳过新 task 的重复步骤
129
+ - `verifySkipKey()` 检查:hash 匹配 + status='completed' + events 表无 `skip_key_consumed`
130
+ - 验证通过后立即写入 `skip_key_consumed` 事件——确保一次性使用
131
+ - 跳过步骤标记为 `skipped`(非 `completed`),保留溯源
132
+
133
+ ---
134
+
135
+ ## 4. DAG 引擎
136
+
137
+ ### 输入格式
138
+ ```json
139
+ {
140
+ "title": "Plan",
141
+ "steps": [
142
+ {"id":"a","title":"A","dependsOn":[]},
143
+ {"id":"b","title":"B","dependsOn":["a"]},
144
+ {"id":"c","title":"C","dependsOn":[],"skipKey":"OLD","skipTaskId":"tsk_OLD"}
145
+ ]
146
+ }
147
+ ```
148
+
149
+ ### 展开规则
150
+ 1. `dependsOn: []` → 并行起点,初始即激活
151
+ 2. `dependsOn: undefined` → 自动串行,依赖前一个叶子
152
+ 3. `dependsOn: ["b","c"]` → b 和 c 都完成后才解锁
153
+ 4. `skipKey + skipTaskId` → 验证通过后标记 `skipped`
154
+ 5. 嵌套 children → 递归展开为叶子节点
155
+
156
+ ### 解锁算法
157
+ ```
158
+ checkpoint(stepX):
159
+ 1. 标记 stepX = completed (保留 key_hash)
160
+ 2. 扫描 pending steps:
161
+ dependsOn 全部 completed/skipped → 标记 current,生成 key
162
+ 3. 无新解锁 + 全部 completed/skipped → 生成 taskKey
163
+ ```
164
+
165
+ ---
166
+
167
+ ## 5. CLI 命令全集 (12 个)
168
+
169
+ ### Task 级
170
+ | 命令 | 输入 | 输出 |
171
+ |------|------|------|
172
+ | `start-plan '<json>'` | title + steps[] | taskId, session, totalSteps, currentSteps, stepKeys |
173
+ | `checkpoint '<json>'` | taskId + stepId + stepKey | completedStep, nextSteps, nextStepKeys, taskKey |
174
+ | `current '<json>'` | taskId | status, totalSteps, completedSteps, currentSteps |
175
+ | `finalize '<json>'` | taskId + taskKey | level(task/node/program), nodeKey(if), program(if) |
176
+ | `cancel-task '<json>'` | taskId | ok / error(NO_SESSION) |
177
+ | `active-task` | — | activeTasks[] (session-filtered) |
178
+ | `active-task --all` | — | activeTasks[] (跨 session) |
179
+
180
+ ### Program 级
181
+ | 命令 | 输入 | 输出 |
182
+ |------|------|------|
183
+ | `program init '<json>'` | title + nodes[] | programId, totalNodes, nodes |
184
+ | `program status '<json>'` | programId | programId, title, nodes[] |
185
+ | `program ready '<json>'` | programId | readyNodes[] |
186
+ | `program start '<json>'` | programId + nodeId | ok, nodeId, sessionId |
187
+ | `program finalize '<json>'` | programId | ok, pending[] |
188
+
189
+ ### Session 绑定方式
190
+ - `--session-file <path>` — 显式指定 session 文件
191
+ - `--binding-file <path>` — 通过 binding 文件间接指定
192
+ - `STEP_GATE_SESSION_FILE` / `STEP_GATE_BINDING_FILE` 环境变量
193
+ - 自动发现 `.step-gate/bindings/` 中最新的 binding(回退)
194
+
195
+ ### Admin 模式
196
+ - `cancel-task --admin --recovery-token <token>` — 跨 session 取消
197
+
198
+ ---
199
+
200
+ ## 6. 核心函数 (20+)
201
+
202
+ ### src/core/plan.ts
203
+ | 函数 | 作用 |
204
+ |------|------|
205
+ | `flattenPlan(nodes, taskId) → LeafStep[]` | 嵌套展开 + DAG 依赖解析 |
206
+
207
+ ### src/core/keys.ts
208
+ | 函数 | 作用 |
209
+ |------|------|
210
+ | `randomCode(length) → string` | [A-Z0-9] 随机码 |
211
+ | `generateStepKey() → {plaintext, hash}` | 6位 step key |
212
+ | `generateTaskKey() → {plaintext, hash}` | 6位 task key |
213
+ | `generateNodeKey() → {plaintext, hash}` | 6位 node key |
214
+ | `hashKey(plaintext) → string` | SHA-256 |
215
+
216
+ ### src/core/gate.ts
217
+ | 函数 | 作用 |
218
+ |------|------|
219
+ | `validateCheckpoint(repo, taskId, stepId, stepKey)` | 5步校验(task存在/active/current匹配/key匹配) |
220
+ | `advanceSteps(repo, task, completedStepId)` | 解锁后继步骤或生成 taskKey |
221
+ | `GateRepository` (interface) | 仓库抽象:getTask/getCurrentSteps/getTaskSteps/completeAndAdvance/updateTaskStatus/verifyTaskKey |
222
+
223
+ ### src/core/session.ts
224
+ | 函数 | 作用 |
225
+ |------|------|
226
+ | `createSession(workspace) → SessionInfo` | 创建 session + 写入文件 |
227
+ | `verifySessionSecret(sessionId, secret)` | 校验 session 凭据 |
228
+ | `verifyRecoveryToken(sessionId, token)` | 校验恢复凭据 |
229
+ | `isSessionActive(sessionId)` | 检查状态 |
230
+ | `getCurrentSessionId()` | 进程内共享 sessionId |
231
+
232
+ ### src/core/program.ts
233
+ | 函数 | 作用 |
234
+ |------|------|
235
+ | `createProgram(title, nodes[]) → ProgramInfo` | 创建 Program |
236
+ | `getProgramStatus(programId) → ProgramInfo` | 查询状态 |
237
+ | `getReadyNodes(programId) → ProgramNodeInfo[]` | 可开始的 node |
238
+ | `startProgramNode(programId, nodeId, sessionId)` | 绑定 session |
239
+ | `commitProgramNode(sessionId)` | 自动生成 nodeKey + 标记 node 完成 |
240
+ | `finalizeProgram(programId)` | 全局完整性检查 |
241
+
242
+ ### src/storage/repository.ts
243
+ | 函数 | 作用 |
244
+ |------|------|
245
+ | `createTask(task, steps[])` | 原子写入 task + steps |
246
+ | `getTask(taskId)` | 查询 task |
247
+ | `getCurrentSteps(taskId)` | 查询活跃步骤 |
248
+ | `getTaskSteps(taskId)` | 查询所有步骤 |
249
+ | `getActiveTasks(sessionId?)` | 活跃 task(可选 session 过滤) |
250
+ | `completeAndAdvance(...)` | 原子完成+推进(事务保护) |
251
+ | `verifyStepKey(taskId, stepId, key)` | 严格校验(status='current') |
252
+ | `verifyTaskKey(taskId, key)` | 校验 taskKey |
253
+ | `verifySkipKey(oldTaskId, stepId, oldKey)` | 验证 skip 凭证 + 检查消费事件 |
254
+ | `recordSkipConsumed(taskId, stepId)` | 写入 skip_key_consumed 事件 |
255
+ | `cancelTask(taskId, sessionId)` | 取消(session 门控) |
256
+ | `updateTaskStatus(taskId, status)` | 更新状态 |
257
+ | `addEvent(taskId, stepId, type, payload?)` | 事件记录 |
258
+ | `getEvents(taskId)` | 查询事件 |
259
+
260
+ ---
261
+
262
+ ## 7. Hook 系统
263
+
264
+ ### SessionStart (`scripts/session-start-hook.sh`)
265
+ ```
266
+ 触发: 每次终端启动
267
+ 策略: 轻量优先 — 读 data/state.json (1ms),无结果才调 CLI
268
+ 行为:
269
+ 1. 读 state.json → 有活跃 task → 警告 + 列出进度
270
+ 2. state 为空 → active-task --all → 跨 session 检查
271
+ 3. 无未完成 → 提醒可用命令
272
+ ```
273
+
274
+ ### Stop (`.claude/settings.local.json`)
275
+ ```
276
+ 触发: Session 结束前
277
+ 行为:
278
+ 调用 finalize(taskKey) → 系统自动传播到 node/program
279
+ 如无 taskKey → 拦截提醒
280
+ ```
281
+
282
+ ### State File (`data/state.json`)
283
+ ```
284
+ 写入时机: start-plan / checkpoint / finalize / cancel-task 后
285
+ 内容: { hasActiveTask, activeTasks: [{taskId, title, completed, total, current}] }
286
+ 用途: SessionStart 1ms 快照,跨互动提醒
287
+ ```
288
+
289
+ ---
290
+
291
+ ## 8. 文件布局
292
+
293
+ ```
294
+ project/
295
+ src/
296
+ cli.ts ← CLI 入口 (504行, 12命令)
297
+ index.ts ← MCP Server 入口 (备用)
298
+ core/
299
+ plan.ts ← DAG 展开
300
+ keys.ts ← 三层密钥生成
301
+ gate.ts ← 校验 + 解锁状态机
302
+ session.ts ← Session 管理
303
+ program.ts ← Program 层
304
+ errors.ts ← GateError
305
+ storage/
306
+ db.ts ← SQLite (WAL, busy_timeout=5000)
307
+ repository.ts ← 数据层 (20+ 函数)
308
+ tools/ ← MCP 工具 (备用)
309
+ startPlan.ts / checkpoint.ts / current.ts
310
+ finalize.ts / cancelTask.ts / activeTask.ts / index.ts
311
+ types/
312
+ index.ts ← 全部类型定义
313
+ tests/
314
+ core.test.ts ← 36 tests
315
+ storage.test.ts ← 34 tests
316
+ tools.test.ts ← 29 tests (含 A1/B1)
317
+ ci-blackbox.test.ts ← 15 tests (MCP 协议级)
318
+ e2e-smoking-app.test.ts ← E2E 强制回退
319
+ e2e-multi-agent.test.ts ← E2E 多Agent协作
320
+ scripts/
321
+ session-start-hook.sh
322
+ prompt-check-hook.sh
323
+ mcp-backup/ ← MCP 完整备份
324
+ data/
325
+ gate.db ← SQLite 数据库
326
+ state.json ← 轻量快照
327
+ .step-gate/
328
+ sessions/ ← Session 凭据文件
329
+ bindings/ ← CLI 绑定文件
330
+ openspec/changes/ ← 变更文档
331
+ SKILL.md ← Skill 定义
332
+ ARCHITECTURE.md ← 本文档
333
+ ```
334
+
335
+ ---
336
+
337
+ ## 9. 错误码
338
+
339
+ | 错误码 | 含义 |
340
+ |--------|------|
341
+ | TASK_NOT_FOUND | taskId 不存在 |
342
+ | TASK_ALREADY_COMPLETED | 任务已完成 |
343
+ | NO_STEPS | 计划无步骤 |
344
+ | INVALID_CURRENT_STEP | 步骤不在当前状态 |
345
+ | INVALID_STEP_KEY | stepKey 校验失败 |
346
+ | INVALID_FINAL_KEY | taskKey 校验失败 |
347
+ | INVALID_RECOVERY_TOKEN | recoveryToken 校验失败 |
348
+ | PLAN_SCHEMA_INVALID | 计划格式错误 |
349
+ | SKIP_VERIFY_FAILED | skip 凭证验证失败或已消费 |
350
+ | NO_SESSION | 无 session 绑定 |
351
+ | INTERNAL_ERROR | 数据库/内部错误 |
352
+
353
+ ---
354
+
355
+ ## 10. 典型流程
356
+
357
+ ### 单 Session
358
+ ```bash
359
+ start-plan → checkpoint × N → finalize taskKey
360
+ # → 自底向上: task → node → program (如有)
361
+ ```
362
+
363
+ ### 中断恢复
364
+ ```bash
365
+ start-plan → checkpoint auth ✅
366
+ → current (查状态) → cancel-task
367
+ → start-plan (skipKey+skipTaskId 重建,旧 key 被消费)
368
+ → checkpoint → finalize taskKey
369
+ ```
370
+
371
+ ### 跨 Session Program
372
+ ```bash
373
+ program init → program start pg-1
374
+ → start-plan → checkpoint × N → finalize taskKey
375
+ # ↑ 自动标记 pg-1 completed + nodeKey 生成
376
+
377
+ program start pg-2
378
+ → start-plan → checkpoint × N → finalize taskKey
379
+ # ↑ 自动标记 pg-2 completed,program completed
380
+ ```
381
+
382
+ ---
383
+
384
+ ## 11. 技术栈
385
+
386
+ - **Runtime**: Node.js 20+
387
+ - **Language**: TypeScript ESM
388
+ - **Storage**: better-sqlite3 (WAL, synchronous=NORMAL, busy_timeout=5000)
389
+ - **Validation**: Zod v4 (MCP tools)
390
+ - **Test**: vitest (116 tests, 6 suites)
391
+ - **Key**: crypto.randomBytes → [A-Z0-9]{6} → SHA-256
392
+ - **IDs**: 6位 [A-Z0-9] (36^6 ≈ 21亿熵)
393
+ - **MCP SDK**: @modelcontextprotocol/sdk v1.x (备用)