@aipper/aiws-spec 0.0.46 → 0.0.48

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.
@@ -386,6 +386,209 @@ export class AiwsContext {
386
386
  )
387
387
  }
388
388
 
389
+ // -- Goal FSM (TOOLING-003D L1 inject) -------------------------------
390
+
391
+ /**
392
+ * Scan `.aiws/goals/*.state.json` for active/paused goals.
393
+ * Preference: status=active first, then paused.
394
+ * Within a status tier, most recently updated wins (updated_at ISO or file mtime).
395
+ *
396
+ * Returns array of goal summary objects (may be empty). Never throws.
397
+ * Each entry:
398
+ * { goal_id, status, current_phase, checkpoint_summary, md_path, state_path,
399
+ * next_action, updated_at, mtime_ms, others_note? }
400
+ */
401
+ getActiveGoals() {
402
+ const goalsDir = join(this.directory, ".aiws", "goals")
403
+ if (!existsSync(goalsDir)) return []
404
+
405
+ let files
406
+ try {
407
+ files = readdirSync(goalsDir).filter(f => f.endsWith(".state.json"))
408
+ } catch {
409
+ return []
410
+ }
411
+
412
+ const active = []
413
+ const paused = []
414
+
415
+ for (const file of files) {
416
+ const statePath = join(goalsDir, file)
417
+ let raw
418
+ try {
419
+ raw = readFileSync(statePath, "utf-8")
420
+ } catch {
421
+ continue
422
+ }
423
+
424
+ let state
425
+ try {
426
+ state = JSON.parse(raw)
427
+ } catch {
428
+ // malformed JSON — skip without crashing
429
+ continue
430
+ }
431
+ if (!state || typeof state !== "object") continue
432
+
433
+ const status = str(state.status)
434
+ if (status !== "active" && status !== "paused") continue
435
+
436
+ const goalId =
437
+ str(state.goal_id) ||
438
+ str(state.goalId) ||
439
+ file.replace(/\.state\.json$/, "")
440
+
441
+ let mtimeMs = 0
442
+ try {
443
+ mtimeMs = statSync(statePath).mtimeMs
444
+ } catch {
445
+ mtimeMs = 0
446
+ }
447
+
448
+ const updatedAt = str(state.updated_at) || str(state.updatedAt) || null
449
+ let sortKey = mtimeMs
450
+ if (updatedAt) {
451
+ const t = Date.parse(updatedAt)
452
+ if (!Number.isNaN(t)) sortKey = t
453
+ }
454
+
455
+ const currentPhase =
456
+ state.current_phase == null
457
+ ? null
458
+ : (str(state.current_phase) || String(state.current_phase))
459
+
460
+ const checkpointSummary = this._summarizeGoalCheckpoints(state.checkpoints)
461
+ const mdPath = join(".aiws", "goals", `${goalId}.md`)
462
+ const nextAction = this._suggestGoalNextAction({
463
+ goal_id: goalId,
464
+ status,
465
+ current_phase: currentPhase,
466
+ checkpoints: state.checkpoints,
467
+ })
468
+
469
+ const entry = {
470
+ goal_id: goalId,
471
+ status,
472
+ current_phase: currentPhase,
473
+ checkpoint_summary: checkpointSummary,
474
+ md_path: mdPath,
475
+ state_path: join(".aiws", "goals", file),
476
+ next_action: nextAction,
477
+ updated_at: updatedAt,
478
+ mtime_ms: mtimeMs,
479
+ _sort: sortKey,
480
+ }
481
+
482
+ if (status === "active") active.push(entry)
483
+ else paused.push(entry)
484
+ }
485
+
486
+ const byRecency = (a, b) => b._sort - a._sort
487
+ active.sort(byRecency)
488
+ paused.sort(byRecency)
489
+
490
+ const ordered = [...active, ...paused]
491
+ return ordered.map(({ _sort, ...rest }) => rest)
492
+ }
493
+
494
+ /**
495
+ * Primary goal for session inject: first of getActiveGoals() (active preferred).
496
+ * When multiple actives exist, the most recently updated is primary; callers can
497
+ * list others via getActiveGoals().
498
+ */
499
+ getActiveGoal() {
500
+ const goals = this.getActiveGoals()
501
+ return goals.length > 0 ? goals[0] : null
502
+ }
503
+
504
+ _summarizeGoalCheckpoints(checkpoints) {
505
+ if (!checkpoints || typeof checkpoints !== "object") return "(no checkpoints)"
506
+ const pending = []
507
+ const complete = []
508
+ for (const [name, cp] of Object.entries(checkpoints)) {
509
+ const st =
510
+ cp && typeof cp === "object"
511
+ ? str(cp.status) || "unknown"
512
+ : "unknown"
513
+ if (st === "complete" || st === "done") complete.push(name)
514
+ else pending.push(`${name}:${st}`)
515
+ }
516
+ const parts = []
517
+ if (pending.length) parts.push(`pending=[${pending.join(", ")}]`)
518
+ if (complete.length) parts.push(`complete=${complete.length}`)
519
+ return parts.join(" ") || "(empty checkpoints)"
520
+ }
521
+
522
+ /**
523
+ * Suggest next_action text for L1 inject (READ-ONLY; no skill execution).
524
+ * Frozen Q3=A: plugins only inject text; model/user runs /ws-goal.
525
+ */
526
+ _suggestGoalNextAction({ goal_id, status, current_phase, checkpoints }) {
527
+ const id = goal_id || "?"
528
+ if (status === "paused") {
529
+ return `/ws-goal resume ${id}`
530
+ }
531
+ // active
532
+ if (!current_phase || current_phase === "null") {
533
+ return `/ws-goal continue ${id} (establish current_phase via advance if needed)`
534
+ }
535
+ // Find first incomplete checkpoint name if useful
536
+ let nextCp = null
537
+ if (checkpoints && typeof checkpoints === "object") {
538
+ for (const [name, cp] of Object.entries(checkpoints)) {
539
+ const st =
540
+ cp && typeof cp === "object" ? str(cp.status) : null
541
+ if (st && st !== "complete" && st !== "done") {
542
+ nextCp = name
543
+ break
544
+ }
545
+ }
546
+ }
547
+ if (nextCp && nextCp !== current_phase) {
548
+ return `/ws-goal continue ${id} — phase=${current_phase}, next checkpoint=${nextCp}`
549
+ }
550
+ return `/ws-goal continue ${id} — phase=${current_phase}`
551
+ }
552
+
553
+ /**
554
+ * Compact <goal-context> block for session-start inject.
555
+ * Empty string when no active/paused goal.
556
+ */
557
+ buildGoalContextBlock() {
558
+ const goals = this.getActiveGoals()
559
+ if (!goals.length) return ""
560
+
561
+ const primary = goals[0]
562
+ const others = goals.slice(1)
563
+ const lines = [
564
+ "<goal-context>",
565
+ "## Active / Paused Goal (FSM L1 inject — advisory routing only)",
566
+ `goal_id: ${primary.goal_id}`,
567
+ `status: ${primary.status}`,
568
+ `current_phase: ${primary.current_phase ?? "null"}`,
569
+ `checkpoints: ${primary.checkpoint_summary}`,
570
+ `goal_md: ${primary.md_path}`,
571
+ `state: ${primary.state_path}`,
572
+ `next_action: ${primary.next_action}`,
573
+ ]
574
+ if (others.length) {
575
+ const brief = others
576
+ .map(g => `${g.goal_id}(${g.status}, phase=${g.current_phase ?? "null"})`)
577
+ .join("; ")
578
+ lines.push(`other_goals: ${brief}`)
579
+ lines.push(
580
+ "note: multiple active/paused — primary is most recently updated; " +
581
+ "resolve conflict before parallel goal work"
582
+ )
583
+ }
584
+ lines.push(
585
+ "authority: phase writes via `aiws goal advance` only; " +
586
+ "this block does not execute skills (L1 text inject)."
587
+ )
588
+ lines.push("</goal-context>")
589
+ return lines.join("\n")
590
+ }
591
+
389
592
  // -- Spec index ------------------------------------------------
390
593
 
391
594
  /**
@@ -824,6 +1027,14 @@ You are starting a new session in an aiws-managed project.
824
1027
  Read and follow the context below.
825
1028
  </aiws-context>`)
826
1029
 
1030
+ // TOOLING-003D L1: active/paused goal FSM inject (READ-ONLY text)
1031
+ try {
1032
+ const goalBlock = ctx.buildGoalContextBlock()
1033
+ if (goalBlock) parts.push(goalBlock)
1034
+ } catch {
1035
+ // Non-blocking: goal inject must never crash session-start
1036
+ }
1037
+
827
1038
  const specIndex = ctx.getSpecIndex()
828
1039
  if (specIndex) {
829
1040
  parts.push("<spec-index>")
@@ -5,21 +5,21 @@ description: 使用时机:新会话开始、不确定下一步做什么时。
5
5
 
6
6
  用中文输出(命令/路径/代码标识符保持原样不翻译)。
7
7
 
8
- 目标:默认入口,先读真值文件,判定当前任务 workflow,再进入具体 `ws-*` skill。若意图不明确:先澄清,不直接进入实现。
8
+ 目标:默认入口,先读真值,判定 workflow,再进入 `ws-*`。意图不明则先澄清,不直接实现。阶段:bootstrap/router,只分流。
9
9
 
10
- 阶段定位:bootstrap/router 阶段;负责分流,不直接完成实现。
10
+ 路由 SSOT:`packages/spec/docs/workflow-router-rules.json`(`goal_driven` / `plan_first` / `direct_implementation` / `escape_hatch`)。本 skill 是人工投影,冲突以 JSON 为准。
11
11
 
12
12
  ## 编排约束
13
13
 
14
- - **不直接实现**:只判 workflow、读真值、路由到对应 `ws-*`。主 session 不直接写代码。
15
- - **上下文先于判决**:路由 `direct_implementation` 前必须收集项目上下文——`git status --porcelain`(改动文件数)、`git diff --stat`(改动行范围)、`AI_WORKSPACE.md` 验证入口。仅当 ≤3 文件、≤100 行改动、验证明确时,才可判 direct。
16
- - **意图不明先澄清**:`routeTo=clarify` 时必须停止并问 1-3 个关键问题,不猜测。
14
+ - **不直接实现**:只判 workflow、读真值、路由到 `ws-*`。主 session 不写代码。
15
+ - **上下文先于判决**:`direct_implementation` 前收集 `git status --porcelain`、`git diff --stat`、`AI_WORKSPACE.md` 验证入口;仅 ≤3 文件、≤100 行、验证明确才可 direct。
16
+ - **意图不明先澄清**:`routeTo=clarify` 时停并问 1-3 个关键问题。
17
+ - **L3 纪律(goal resume)**:有 `active`/`paused` goal 时,冷启动 medium+ 勿 bare 跳 `$ws-dev`/`$ws-plan`;优先 `$ws-goal` resume。例外:显式 escape-hatch 或用户点名阶段 skill。
17
18
 
18
19
  ## 必需输入
19
20
 
20
- - 当前任务描述
21
- - `AI_PROJECT.md` / `REQUIREMENTS.md` / `AI_WORKSPACE.md`
22
- - 若已存在:`change/<change-id>` 上下文、`plan/...`、`.aiws/changes/<change-id>/...`
21
+ - 任务描述;`AI_PROJECT.md` / `REQUIREMENTS.md` / `AI_WORKSPACE.md`
22
+ - 若已存在:`change/<id>`、`plan/...`、`.aiws/changes/<id>/...`、`.aiws/goals/`、`ws-goal` skill
23
23
 
24
24
  ## 必需输出
25
25
 
@@ -27,83 +27,74 @@ description: 使用时机:新会话开始、不确定下一步做什么时。
27
27
 
28
28
  ## 阻断条件
29
29
 
30
- - 无法确定项目根目录、缺失任一真值文件、无法明确任务意图、无法归因且不能安全推断
30
+ - 无法确定项目根、缺失真值、意图不明、无法归因且不能安全推断
31
31
 
32
32
  ## 执行步骤
33
33
 
34
34
  ### 1. Preflight
35
35
 
36
- 读取 `AI_PROJECT.md` / `REQUIREMENTS.md` / `AI_WORKSPACE.md`。若检测到 `.opencode/oh-my-opencode.json` 输出 `oMo-enabled`,否则 `standard-opencode`。缺失真值文件则 route = `$ws-preflight`,建议 `aiws init .`
36
+ 读三真值。有 `.opencode/oh-my-opencode.json` `oMo-enabled`,否则 `standard-opencode`。缺真值 `$ws-preflight`,建议 `aiws init .`。
37
37
 
38
38
  ### 1.5 Per-turn Breadcrumb(必做)
39
39
 
40
- 每轮对话开始时读取当前 change 状态,输出 `[workflow-state:PHASE_NAME/N]` 标记。
40
+ 每轮开始读 change 状态,输出 `[workflow-state:PHASE_NAME/N]`。
41
41
 
42
42
  ### 2. 路由判定
43
43
 
44
- 根据 `packages/spec/docs/workflow-router-rules.json` 判定。判 direct_implementation 前必须先收集上下文(git status、涉及文件范围):
44
+ `workflow-router-rules.json` 判定。direct 前先收集 git 上下文。
45
45
 
46
- - ≤2 文件且均在已知路径 → direct
47
- - ≥3 文件或含未知路径 → ws-plan
46
+ **复杂度启发(结合上下文):** ≤2 文件、已知路径、≤100 行、验证明确 direct;≥3 文件 / 跨模块 / 多步 / 未知路径 → medium+(优先 goal/plan)。
47
+
48
+ **ws-goal 可用**:存在 `.aiws/goals/`,或可加载 `ws-goal` skill。
48
49
 
49
50
  | 意图 | Route |
50
51
  |------|-------|
51
52
  | 需求/验收/合同变更 | `$ws-req-review` |
52
- | 评审/审计/找风险 | `$ws-review` |
53
+ | 评审/审计/风险 | `$ws-review` |
53
54
  | finish/merge/push/cleanup | `$ws-finish` |
54
55
  | handoff/archive | `$ws-handoff` |
55
- | 先出设计方案 | `$ws-plan`(设计作为 plan 阶段一部分) |
56
- | 更新规范/验收标准 | `$ws-req-change`(需求变更需先 review) |
57
- | 中大型实现 | `$ws-plan` |
56
+ | 先出设计方案 | `$ws-plan`(已走 goal `$ws-goal` 管道) |
57
+ | 更新规范/验收 | `$ws-req-change`(先 review) |
58
+ | 中大型实现(goal 可用) | `$ws-goal`(`goal_driven`) |
59
+ | 中大型实现(goal 不可用) | `$ws-plan`(`plan_first`) |
58
60
  | 小步明确实现/修复 | `$ws-dev` |
59
- | 极简修复 | `$ws-dev-lite` |
60
- | Subagent 不可用 | 回退单 agent + 工件模式 |
61
-
62
- 注:`$ws-dev` 默认走 subagent-first 策略。主 session 应优先通过 `$ws-delegate` 派发 `aiws-worker`,除非用户明确说"直接改"。
61
+ | 极简修复 / 显式跳过流程 | `$ws-dev-lite`(后者 `escape_hatch`) |
62
+ | Subagent 不可用 | agent + 工件模式 |
63
63
 
64
- **Escape Hatch**:用户明确说"跳过流程"时允许 direct_implementation,但须输出 `[escape-hatch]` 标记、归因到 Req_ID、有可复现验证入口、落盘 evidence 注明原因。
64
+ 注:`$ws-dev` 默认 subagent-first;主 session 优先 `$ws-delegate` `aiws-worker`,除非用户说「直接改」。
65
65
 
66
+ **Escape Hatch**:用户明确「跳过流程」/「直接改」/「do it inline」→ `$ws-dev-lite`,须 `[escape-hatch]`、Req_ID、可复现验证、evidence 注明原因。小修入口保留,不得全灌 `$ws-goal`。
66
67
  ### 3. 意图不明确
67
68
 
68
69
  只问 1-3 个关键问题(意图、Req_ID/Problem_ID、verify、change),然后停止。
69
70
 
70
71
  ### 4. Continuation Routing(新 session 恢复)
71
72
 
72
- 续跑决策:
73
-
74
- | Phase | Next Action |
75
- |-------|-------------|
76
- | none(无 change) | ws-intake 或 ws-plan |
77
- | intake | ws-intake 继续,或 ws-plan |
78
- | planning | plan 存在→ws-plan-verify;否则 ws-plan |
79
- | ready-for-dev | 派发 aiws-worker |
80
- | in-progress | patches 存在→review;was DONE_WITH_CONCERNS→ws-quality-review;否则继续 |
81
- | review | evidence 齐→ws-finish/ws-commit;否则补 evidence |
82
- | finished | ws-finish 收尾归档 |
83
- | unknown | ws-preflight |
73
+ change 相位 + goal 叠加;goal 优先于冷启动 plan/dev 跳过:
84
74
 
85
- Subagent 降级:无 subagent 时当前 agent 直接执行,evidence 中记录降级原因(`mode: single-agent`)。
75
+ | Phase / Goal | Next |
76
+ |--------------|------|
77
+ | active goal | `$ws-goal` resume(按 state next_action) |
78
+ | paused goal | `$ws-goal` resume(继续 / 改目标 / 放弃后冷启动) |
79
+ | none | intake;或 medium+ 且 goal 可用 → `$ws-goal`;否则 `$ws-plan` |
80
+ | intake | 继续 intake,或 plan/goal(按可用性与冻结) |
81
+ | planning | 有 plan→plan-verify;否则 plan(goal 内则 `$ws-goal`) |
82
+ | ready-for-dev | 派发 aiws-worker(goal 绑定经 `$ws-goal`) |
83
+ | in-progress | 有 patches→review;DONE_WITH_CONCERNS→quality-review;否则继续 |
84
+ | review | evidence 齐→finish/commit;否则补 evidence |
85
+ | finished / unknown | `$ws-finish` 归档 / `$ws-preflight` |
86
86
 
87
- 特殊状态:`BLOCKED` 需解 blocker;`NEEDS_CONTEXT` 补 JSONL 后重试。
87
+ Subagent 降级:无 subagent 时本 agent 执行,evidence 记 `mode: single-agent`。`BLOCKED` blocker;`NEEDS_CONTEXT` 补 JSONL 后重试。
88
88
 
89
89
  ### 5. 输出路由
90
90
 
91
91
  ```
92
- Root: <path>
93
- Found: <files>
94
- OpenCode mode: <oMo-enabled / standard-opencode>
95
- Task intent: <分类>
96
- Binding: <清晰 / 缺失项>
97
- Route: <$ws-... 或 clarify>
98
- Why: <一句到三句>
99
- Next: <继续执行对应 skill,或提出澄清问题>
92
+ Root: / Found: / OpenCode mode: / Task intent: / Binding: / Route: / Why: / Next:
100
93
  ```
101
94
 
102
95
  ## 约束
103
96
 
104
- - Router 自己不实现代码;不给 route 前不直接改代码
105
- - 一次只选一个主 route
106
- - 复杂度升高:`$ws-dev` 回退 `$ws-plan`;`$ws-finish` 回退前置门禁
107
- - subagent 不可用:单 agent 执行,但须维护等价工件结构
97
+ - Router 不实现;不给 route 前不改代码;一次一个主 route;复杂度升高时 `$ws-dev` → `$ws-plan`/`$ws-goal`,`$ws-finish` 回退前置门禁
98
+ - subagent 不可用:单 agent,维护等价工件;不用 L4 程序化 skill invoke(agent 读规则后进入 skill)
108
99
 
109
100
  > 运行时行为约束:`packages/spec/docs/run-behavior-guidelines.md`
@@ -5,67 +5,46 @@ description: 使用时机:需要拆分子任务、委托给子 agent 时。触
5
5
 
6
6
  用中文输出(命令/路径/代码标识符保持原样不翻译)。
7
7
 
8
- 目标:优先借用 oMo agent 做任务拆分;若不可用,回退普通 OpenCode delegation / 单 agent。
8
+ 目标:优先 oMo agent 拆分任务;不可用则回退 OpenCode delegation / 单 agent。
9
9
 
10
10
  ## 核心约束
11
11
 
12
- - **Subagent-First**:主 session 只做编排收敛,不直接写代码。所有产出由 subagent 完成并可追溯。
13
- - **Handoff 证据**:worker 必须产出 `.aiws/changes/<id>/handoff-evidence.md`(完成项、未完成项、残余风险)。文件缺失=委托未完成。
12
+ - **Subagent-First**:主 session 只编排收敛,不写代码;产出由 subagent 完成并可追溯。
13
+ - **Handoff 证据**:worker 必须产出 `.aiws/changes/<id>/handoff-evidence.md`(完成/未完成/残余风险)。缺失=委托未完成。
14
14
 
15
- ## 必需输入
15
+ ## 必需输入 / 输出
16
16
 
17
- - 真值文件 + delegation contract 等上下文(`workflow-delegation-contracts.md`、`opencode-omo-adapter.md`、`opencode-subagent-first.md`)
18
- - 当前任务已绑定 `Req_ID` / change / Verify
17
+ **输入:** 真值 + delegation contract 上下文(`workflow-delegation-contracts.md`、`opencode-omo-adapter.md`、`opencode-subagent-first.md`);任务已绑定 `Req_ID` / change / Verify。
19
18
 
20
- ## 必需输出
19
+ **输出:** `Delegation Plan:` role / preferred agent / readScope / writeScope / artifactTargets / fallback;`Context Curation:` / `Execution Mode:` / `Evidence:` / `Next:`。
21
20
 
22
- - `Delegation Plan:` role / preferred agent / readScope / writeScope / artifactTargets / fallback
23
- - `Context Curation:` 策展详情 / `Execution Mode:` / `Evidence:` / `Next:`
21
+ **执行:** session 不改代码;产物由 subagent 可追溯产出;handoff delegate round number、产出路径、未关闭项。
24
22
 
25
- ## 执行要求
26
-
27
- - 主 session 不直接改代码;所有产物由 subagent 产出且可追溯
28
- - handoff 含 delegate round number、产出文件路径、已知未关闭项
29
-
30
- ## 阻断条件
31
-
32
- 任务未绑定 / 委托边界不清 / 上下文策展未执行 / 无法判断 oMo 可用性 / handoff 文件缺失
23
+ **阻断:** 任务未绑定 / 边界不清 / 未策展上下文 / 无法判断 oMo 可用性 / handoff 缺失。
33
24
 
34
25
  ## 角色映射
35
26
 
36
- | aiws 角色 | oMo Agent |
37
- |-----------|-----------|
38
- | planner | planner-sisyphus |
39
- | explorer | @explore / @librarian |
40
- | reviewer | @oracle |
41
- | integrator | 当前主 agent |
42
-
43
- 推荐标准角色:
44
-
45
- | 角色 | 职责 | 读取 | 写入 |
46
- |------|------|------|------|
47
- | implementer | 代码+测试实现 | 真值+change上下文 | 代码+测试+evidence/ |
48
- | reviewer | 独立审查 | 真值+diff+evidence | review/*.md |
49
- | researcher | 分析探索 | 真值+外部文档 | analysis/*.md |
27
+ | aiws | oMo | 标准角色 | 职责 | 读 | 写 |
28
+ |------|-----|----------|------|----|----|
29
+ | planner | planner-sisyphus | implementer | 代码+测试 | 真值+change | 代码+测试+evidence/ |
30
+ | explorer | @explore / @librarian | reviewer | 独立审查 | 真值+diff+evidence | review/*.md |
31
+ | reviewer | @oracle | researcher | 分析探索 | 真值+外部文档 | analysis/*.md |
32
+ | integrator | 当前主 agent | | | | |
50
33
 
51
34
  ## 连续执行循环
52
35
 
53
- 1. 主 session 策展上下文 JSONL → dispatch `aiws-worker`
54
- 2. 检查返回状态(DONE / DONE_WITH_CONCERNS / NEEDS_CONTEXT / BLOCKED
55
- 3. DONE → dispatch `aiws-reviewer`;pass→收敛 evidence;fail→worker 修复(≤3 次)
36
+ 1. 主 session 策展 JSONL → dispatch `aiws-worker`
37
+ 2. 检查 Status:DONE / DONE_WITH_CONCERNS / NEEDS_CONTEXT / BLOCKED
38
+ 3. DONE → dispatch `aiws-reviewer`;pass→收敛 evidence;fail→worker 修复(≤3
56
39
  4. DONE_WITH_CONCERNS → 先 `ws-quality-review`
57
- 5. NEEDS_CONTEXT → 补上下文重试(≤2 次);仍失败→回退单 agent
58
- 6. BLOCKED → 输出 blocker 详情,不继续
40
+ 5. NEEDS_CONTEXT → 补上下文重试(≤2);仍失败→回退单 agent
41
+ 6. BLOCKED → 输出 blocker,不继续
59
42
 
60
43
  ## 上下文策展
61
44
 
62
- 1. 读取合同基线的 `contextFiles`
63
- 2. 展开 glob(替换 `<id>`)
64
- 3. 委托者调整(添加/删除/调整 priority/sections)
65
- 4. 预算检查:high+medium ≤5 文件,总行数 ≤4000
66
- 5. 写入 `.aiws/changes/<id>/analysis/<role>-context.jsonl`
45
+ 1. 读合同 `contextFiles` → 2. 展开 glob(`<id>`)→ 3. 委托者调整(增删/priority/sections)→ 4. 预算 high+medium ≤5 文件、总行 ≤4000 → 5. 写 `.aiws/changes/<id>/analysis/<role>-context.jsonl`
67
46
 
68
- 插件 `aiws-inject-context` 自动注入 JSONL——在 `task()` 中指定 `role: <role>` 即可。
47
+ 插件 `aiws-inject-context` 自动注入;`task()` 指定 `role: <role>` 即可。
69
48
 
70
49
  ## 子 agent 返回协议
71
50
 
@@ -91,13 +70,10 @@ Context Curation: .aiws/changes/<id>/analysis/worker-context.jsonl
91
70
 
92
71
  ## 委托者检查清单
93
72
 
94
- 派遣前:`[ ] prompt 含上下文引用` `[ ] JSONL 已写入` `[ ] 预算检查通过` `[ ] readScope/writeScope/artifactTargets 已声明`
73
+ **派遣前:** `[ ] prompt 含上下文引用` `[ ] JSONL 已写` `[ ] 预算通过` `[ ] readScope/writeScope/artifactTargets 已声明`
95
74
 
96
- 返回后:`[ ] 解析 Status` `[ ] 非 DONE→按规则处理` `[ ] 非 DONE→记录决策到 delegation-decisions.md` `[ ] handoff 文件存在且非空`
75
+ **返回后:** `[ ] 解析 Status` `[ ] 非 DONE→按规则处理` `[ ] 非 DONE→记入 delegation-decisions.md` `[ ] handoff 存在且非空`
97
76
 
98
- 安全:
99
- - 不让 `ws-delegate` 变成第二套 orchestrator
100
- - 不让 delegated agent 越权写未授权文件
101
- - 不跳过 submodule drift check(若 `.gitmodules` 存在)
77
+ **安全:** 不把 `ws-delegate` 做成第二套 orchestrator;delegated agent 不越权写未授权文件;有 `.gitmodules` 时不跳过 submodule drift check。
102
78
 
103
79
  > 运行时行为约束:`packages/spec/docs/run-behavior-guidelines.md`
@@ -5,23 +5,18 @@ description: 使用时机:需要修改代码、配置、测试时。触发词
5
5
 
6
6
  用中文输出(命令/路径/代码标识符保持原样不翻译)。
7
7
 
8
- 目标:在 AIWS 约束下完成一个可回放、可验证的小步交付。
9
-
10
- 阶段定位:implementation 阶段。
8
+ 目标:在 AIWS 约束下完成可回放、可验证的小步交付。阶段:implementation。
11
9
 
12
10
  ## 必需输入
13
11
 
14
- - 真值文件:`AI_PROJECT.md` / `REQUIREMENTS.md` / `AI_WORKSPACE.md`
15
- - 当前任务的归因目标(`Req_ID` 或 `Problem_ID`)
16
- - 若为 medium/complex:已通过 `$ws-plan` / `$ws-plan-verify` 的计划
17
- - 当前 `change/<change-id>` 上下文或等价变更归因
12
+ - 真值:`AI_PROJECT.md` / `REQUIREMENTS.md` / `AI_WORKSPACE.md`
13
+ - 归因:`Req_ID` 或 `Problem_ID`;`change/<change-id>` 上下文
14
+ - medium/complex:已通过 `$ws-plan` / `$ws-plan-verify` 的计划
18
15
 
19
16
  ## 必需输出
20
17
 
21
- - `变更文件(Changed):` 实际改动清单
22
- - `验证(Verify):` 实际运行的命令与结果
23
- - `证据(Evidence):` `plan/...`、`.aiws/changes/<change-id>/...` 等证据路径
24
- - `Next:` 若准备提交,建议 `$ws-review` 或 `$ws-commit`
18
+ - `变更文件(Changed):` / `验证(Verify):` / `证据(Evidence):` 路径
19
+ - `Next:` 准备提交时建议 `$ws-review` 或 `$ws-commit`
25
20
 
26
21
  ## 前置条件(硬阻断 — 必须最先检查)
27
22
 
@@ -33,58 +28,46 @@ description: 使用时机:需要修改代码、配置、测试时。触发词
33
28
 
34
29
  ## TDD 约束(强制)
35
30
 
36
- 对于编写新代码或修改业务逻辑的任务,必须遵守 RED-GREEN-REFACTOR:
37
- 1. **RED**:先写测试,运行并确认测试失败
38
- 2. **GREEN**:最小实现使测试通过
39
- 3. **REFACTOR**:重构,保持测试通过
40
- 禁止:先写实现再补测试 / 跳过测试直接提交。
41
- 修改后自检:`lint → typecheck → test`(项目无对应脚本则跳过)。
31
+ 新代码/业务逻辑改动必须 RED-GREEN-REFACTOR:
32
+ 1. **RED**:先写测试并确认失败 → 2. **GREEN**:最小实现通过 → 3. **REFACTOR**:保持绿
33
+ 禁止先实现后补测 / 跳过测试提交。改后自检:`lint → typecheck → test`(无脚本则跳过)。
42
34
 
43
35
  ## 完成判定
44
36
 
45
- 改动已落盘、验证已执行或已说明未执行原因、证据路径可回放,可进入 review/commit。
37
+ 改动已落盘、验证已执行或已说明未执行原因、证据可回放 → 可进 review/commit。
46
38
 
47
39
  ## 建议流程
48
40
 
49
41
  ### 1. Preflight
50
42
 
51
- 定位项目根,读取真值文件,输出约束摘要。
52
- - 中大型任务:先用 `$ws-plan` 生成 `plan/` 工件,并默认执行 3.1 自我修正循环
53
- - 已有计划:先 `$ws-plan-verify`,通过后进入实现
54
- - `$ws-plan` 已创建 worktree:直接在其中继续
43
+ 定位项目根,读真值,输出约束摘要。中大型先 `$ws-plan`(默认走 3.1);已有计划先 `$ws-plan-verify`;已有 worktree 则直接继续。
55
44
 
56
45
  ### 1.5 Spec Refresh(进入实现前必做)
57
46
 
58
- 重读 `AI_PROJECT.md` 安全边界和 `REQUIREMENTS.md` 相关条目,输出 2-3 段摘要。避免遗忘约束或需求边界。
47
+ 重读 `AI_PROJECT.md` 安全边界与 `REQUIREMENTS.md` 相关条目,输出 2-3 段摘要。
59
48
 
60
49
  ### 2. 建立变更归因
61
50
 
62
- - `git status --porcelain` 仅有计划/工件文件 → 继续
63
- - 创建新 change:`aiws change start <change-id> --hooks --no-switch`
64
- - 切换分支:先确认无未提交改动,再 `git switch change/<change-id>`
65
- - 有 submodule:准备好 `submodules.targets`(`aiws change start` 自动检测 `.gitmodules`)
51
+ - `git status --porcelain` 仅有计划/工件 → 继续
52
+ - 新建:`aiws change start <change-id> --hooks --no-switch`;切换前确认无未提交改动再 `git switch change/<change-id>`
53
+ - submodule:准备 `submodules.targets`(`aiws change start` 自动检测 `.gitmodules`)
66
54
 
67
55
  ### 3. 实现策略:默认 dispatch aiws-worker(Subagent-First)
68
56
 
69
57
  详见 `packages/spec/docs/opencode-subagent-first.md`。
70
- - 主 session **默认不直接写代码**;通过 `$ws-delegate` 派发 `aiws-worker`(`task()` 中加 `role: worker`)
71
- - worker 返回后派发 `aiws-reviewer` 独立审查,根据结果 fix 或收敛 evidence
72
- - **Inline escape hatch**:用户说"直接改"或"do it inline"时可直接写代码,但必须落盘记录理由
73
- - 验证先行:先确认 `AI_WORKSPACE.md` 中验证命令;不明确则先补验证入口再实现
58
+ - 主 session **默认不直接写代码**;`$ws-delegate` 派发 `aiws-worker`(`task()` `role: worker`)
59
+ - worker 返回后派发 `aiws-reviewer` 独立审查,再 fix 或收敛 evidence
60
+ - **Inline escape hatch**:用户说"直接改"/`do it inline` 时可直写,须落盘记录理由
61
+ - 验证先行:确认 `AI_WORKSPACE.md` 验证命令;不明确则先补入口再实现
74
62
 
75
63
  ### 3.1 自我修正循环(evaluate-optimize)——必经步骤
76
64
 
77
- dispatch 前最多 **2 轮** 自审+修正:subagent 产出 → 主 session 检查(lint/typecheck/代码模式)→ 有问题则要求修正 2 轮后仍有问题升级到 `$ws-review`。
78
- 适用:所有非 trivial 改动。注意:不替代 `$ws-review` 正式 gate。
65
+ dispatch 前最多 **2 轮**:产出 → 主 session 检查(lint/typecheck/模式)→ 有问题则修正;2 轮后仍有问题升级 `$ws-review`。适用非 trivial;不替代 `$ws-review` 正式 gate。
79
66
 
80
67
  ### 4. 其他规则
81
68
 
82
- - 需求调整:`$ws-req-review` → 确认后 `$ws-req-change`
83
- - 最小改动:每处改动归因到 `REQUIREMENTS.md` `issues/problem-issues.csv`
84
- - 验证:运行 `AI_WORKSPACE.md` 命令;未运行不声称已运行
85
- - 多步任务用 `update_plan` 跟踪
86
- - 提交前门禁:`aiws validate .`
87
- - 交付收尾:`$ws-finish`
69
+ - 需求调整:`$ws-req-review` → `$ws-req-change`;最小改动归因到 `REQUIREMENTS.md` 或 `issues/problem-issues.csv`
70
+ - 验证跑 `AI_WORKSPACE.md` 命令(未运行不声称已运行);多步用 `update_plan`;提交前 `aiws validate .`;收尾 `$ws-finish`
88
71
 
89
72
  ## 输出要求
90
73
 
@@ -23,34 +23,21 @@ description: 使用时机:需要前端设计、UI/UX 实现时。触发词:
23
23
  - `Interaction thesis:` 2-3 个动效想法及其如何改善层级/氛围/可感知性
24
24
 
25
25
  ## 设计默认值
26
- - 从构图开始,不从组件库开始
27
- - 第一屏优先海报感(poster),不是文档感(document)
28
- - 默认先找强视觉锚点:大图、主视觉平面、关键产品画面、主数据工作区
29
- - 默认不做卡片墙;优先 section / column / divider / media block / list / plain layout
30
- - 默认最多两套字体、一种强调色;已有品牌系统则优先跟随
31
- - 优先靠留白、尺度、裁切、对比、对齐建立层级,再考虑装饰
26
+ - 构图优先于组件库;第一屏偏海报感,非文档感
27
+ - 强视觉锚点:大图 / 主视觉平面 / 产品画面 / 主数据工作区
28
+ - 避免卡片墙;用 section / column / divider / media / list / plain layout
29
+ - ≤两套字体、一种强调色(有品牌系统则跟随);靠留白、尺度、裁切、对比、对齐建层级
32
30
 
33
31
  ## Landing 规则
34
- 默认结构:
35
- - Hero:品牌/产品名、承诺、CTA、一个主视觉
36
- - Support:一个具体能力 / 证明点
37
- - Detail:氛围、流程、产品深度或故事
38
- - Final CTA:开始、注册、联系、访问
39
- Hero 强约束:
40
- - 一个 section 只承载一个 dominant idea
41
- - 默认 full-bleed hero;仅内层文字列约束宽度
42
- - 品牌名 > headline > body > CTA
43
- - 不要 hero cards / stat strips / logo clouds / pill soup / floating dashboards
44
- - headline desktop 约 2-3 行;mobile 一眼读完
45
- - 有固定 header 时占用首屏预算;header + hero 不超出 viewport
46
- - 若去掉主视觉后首屏仍几乎成立,说明图像太弱
32
+ 结构:Hero(名/承诺/CTA/主视觉)→ Support(能力/证明)→ Detail(氛围/流程/故事)→ Final CTA
33
+ Hero:每 section 一个 dominant idea;默认 full-bleed(仅文字区限宽);品牌名 > headline > body > CTA
34
+ 禁止:hero cards / stat strips / logo clouds / pill soup / floating dashboards
35
+ headline desktop 约 2-3 行、mobile 一眼读完;header+hero 不超 viewport;主视觉去掉后首屏仍成立=图像太弱
47
36
 
48
37
  ## App-UI 规则
49
- - 偏克制:少颜色、少 chrome、清晰栅格、密度适中、信息可扫读
50
- - 优先组织为 primary workspace navigation → secondary context → action
51
- - card 只用作交互容器;否则改回 plain layout
52
- - 不要把常规产品 UI 做成营销落地页
53
- - 文案优先 orientation / status / action;不要首页口号 / 情绪隐喻 / 执行摘要横幅
38
+ - 克制:少色、少 chrome、清晰栅格、可扫读;primary workspace → nav → secondary context → action
39
+ - card 仅作交互容器,否则 plain layout;勿把产品 UI 做成营销页
40
+ - 文案偏 orientation / status / action;忌口号 / 情绪隐喻 / 摘要横幅
54
41
 
55
42
  ## 图像与媒体
56
43
  - 图像必须承担叙事任务,不能只是补背景
@@ -78,14 +65,9 @@ Hero 强约束:
78
65
  - 图像上的文字必须保证对比度与点击区域可用
79
66
  - 必须同时考虑 desktop / mobile;验证命令优先引用 `AI_WORKSPACE.md`
80
67
 
81
- ## 硬规则
82
- 默认不堆卡片 / hero cards / SaaS card grid。每 section 一个 dominant idea。最多两套字体、一种强调色。产品 UI 后不加装饰渐变,图像后不堆文字,不用 filler copy。
83
-
84
- ## 实现检查(交付前自检)
85
- - 第一屏能否一眼看出品牌/产品;是否有明确视觉锚点
86
- - 只扫标题能否理解页面;每个 section 是否只有一个职责
87
- - card 是否真有必要;动效是否真正提升层级/氛围
88
- - 去掉装饰阴影后页面是否仍成立
68
+ ## 实现检查(交付前)
69
+ - 首屏品牌/锚点明确;扫标题即可懂页;每 section 单一职责
70
+ - card 有必要;动效真提升层级;去装饰阴影后页面仍成立
89
71
 
90
72
  ## 输出要求
91
73
  - `Mode:` `landing | app-ui | polish-only`