@ai-content-space/loopx 0.1.7 → 0.1.9

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 CHANGED
@@ -498,6 +498,7 @@ node --test test/*.test.mjs
498
498
  node scripts/install-skills.mjs --check
499
499
  node --test plugins/loopx/scripts/plugin-install.test.mjs
500
500
  node src/cli.mjs --help
501
+ node src/cli.mjs --version
501
502
  node src/cli.mjs doctor
502
503
  node src/cli.mjs status --json
503
504
  ```
@@ -521,4 +522,4 @@ node src/cli.mjs status --json
521
522
 
522
523
  ## Version
523
524
 
524
- Current npm package version: `0.1.7`.
525
+ Current npm package version: `0.1.9`.
package/README.zh-CN.md CHANGED
@@ -509,6 +509,7 @@ node --test test/*.test.mjs
509
509
  node scripts/install-skills.mjs --check
510
510
  node --test plugins/loopx/scripts/plugin-install.test.mjs
511
511
  node src/cli.mjs --help
512
+ node src/cli.mjs --version
512
513
  node src/cli.mjs doctor
513
514
  node src/cli.mjs status --json
514
515
  ```
@@ -532,4 +533,4 @@ node src/cli.mjs status --json
532
533
 
533
534
  ## 版本
534
535
 
535
- 当前 npm 包版本:`0.1.7`。
536
+ 当前 npm 包版本:`0.1.9`。
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ai-content-space/loopx",
3
3
  "type": "module",
4
- "version": "0.1.7",
4
+ "version": "0.1.9",
5
5
  "description": "Skill-first loopx workflow product for Codex",
6
6
  "repository": {
7
7
  "type": "git",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "loopx",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "Skill-first loopx workflow product for Codex",
5
5
  "skills": "./skills/",
6
6
  "interface": {
@@ -3,7 +3,7 @@ name: archive
3
3
  description: "Archives an approved loopx change delta into long-lived specs and writes an ADR candidate after done approval. Not for active builds or unapproved reviews."
4
4
  when_to_use: "archive, done workflow, spec delta, long-lived specs, ADR candidate, review approved, 归档, 同步规格"
5
5
  metadata:
6
- version: "0.1.7"
6
+ version: "0.1.9"
7
7
  argument-hint: "<workflow slug>"
8
8
  ---
9
9
 
@@ -3,7 +3,7 @@ name: autopilot
3
3
  description: "Runs one bounded autonomous loopx orchestration over clarify, plan, build, and review while preserving canonical artifacts. Not for manual gate-by-gate control."
4
4
  when_to_use: "autopilot, autonomous loopx run, end-to-end workflow, run all stages, bounded orchestration, 自动执行, 全流程"
5
5
  metadata:
6
- version: "0.1.7"
6
+ version: "0.1.9"
7
7
  argument-hint: "<workflow slug>"
8
8
  ---
9
9
 
@@ -3,7 +3,7 @@ name: build
3
3
  description: "Executes an approved loopx plan or review rework contract with evidence, verification, deslop, and regression gates. Not for unclear requirements or independent review."
4
4
  when_to_use: "build, implement approved plan, execute PRD, --from-review, review rework, implementation fixes, 执行, 实现, 修改"
5
5
  metadata:
6
- version: "0.1.7"
6
+ version: "0.1.9"
7
7
  argument-hint: "[--no-deslop] <approved PRD path or workflow slug> | --from-review <review artifact path>"
8
8
  ---
9
9
 
@@ -3,7 +3,7 @@ name: clarify
3
3
  description: "Clarifies ambiguous loopx work into requirements, non-goals, decision boundaries, and design-ready specs before planning. Not for already-approved plans or concrete implementation tasks."
4
4
  when_to_use: "clarify, requirements, ambiguous request, unclear scope, non-goals, decision boundaries, acceptance criteria, 需求澄清, 范围不清"
5
5
  metadata:
6
- version: "0.1.7"
6
+ version: "0.1.9"
7
7
  ---
8
8
 
9
9
  # loopx Clarify
@@ -3,7 +3,7 @@ name: debug
3
3
  description: "Finds root cause for bugs, failing tests, build failures, regressions, and unexpected behavior before fixes. Not for new feature planning or routine code review."
4
4
  when_to_use: "debug, bug, test failure, build failure, regression, unexpected behavior, root cause, 报错, 失败, 回归, 排查"
5
5
  metadata:
6
- version: "0.1.7"
6
+ version: "0.1.9"
7
7
  ---
8
8
 
9
9
  # Systematic Debugging
@@ -3,7 +3,7 @@ name: go-style
3
3
  description: "Applies loopx Go coding style for .go edits, tests, errors, context, naming, and interface boundaries. Not for non-Go code or Kratos-specific architecture by itself."
4
4
  when_to_use: "go-style, Go, golang, .go files, go tests, gofmt, idiomatic Go, Go style, Go 代码"
5
5
  metadata:
6
- version: "0.1.7"
6
+ version: "0.1.9"
7
7
  ---
8
8
 
9
9
  # Go Style
@@ -3,7 +3,7 @@ name: kratos
3
3
  description: "Supports Go-Kratos microservices, proto/buf APIs, service/biz/data layers, middleware, auth, config, and troubleshooting. Not for generic Go style alone."
4
4
  when_to_use: "kratos, Go-Kratos, proto, buf, service layer, biz layer, data layer, middleware, auth, config, Kratos 微服务"
5
5
  metadata:
6
- version: "0.1.7"
6
+ version: "0.1.9"
7
7
  ---
8
8
 
9
9
  # Kratos
@@ -3,7 +3,7 @@ name: plan
3
3
  description: "Creates a consensus-first loopx plan package with Planner, Architect, and Critic review from an approved spec. Not for unresolved requirements or direct implementation."
4
4
  when_to_use: "plan, planning, consensus planning, PRD, architecture plan, test plan, approved clarify spec, 规划, 方案, 架构评审"
5
5
  metadata:
6
- version: "0.1.7"
6
+ version: "0.1.9"
7
7
  argument-hint: "[--interactive] [--deliberate] [--direct <spec-path>] <clarified task or spec path>"
8
8
  ---
9
9
 
@@ -3,7 +3,7 @@ name: review
3
3
  description: "Reviews a loopx build execution record for acceptance, code risks, evidence quality, and architecture smells. Not for doing implementation work or replanning."
4
4
  when_to_use: "review, code review, acceptance, go no-go, execution-record, architecture smell, build complete, 审查, 验收"
5
5
  metadata:
6
- version: "0.1.7"
6
+ version: "0.1.9"
7
7
  argument-hint: "<execution-record path or workflow slug>"
8
8
  ---
9
9
 
@@ -101,13 +101,16 @@ For approval:
101
101
 
102
102
  ```text
103
103
  Next:
104
- loopx approve <slug> --from review --to done
104
+ $archive <slug>
105
105
  ```
106
106
 
107
- After the workflow reaches `done`, run:
107
+ `$archive` consumes the pending `review -> done` completion transition before syncing specs. Do not ask the user to run a separate `loopx approve <slug> --from review --to done` command in the normal Codex-facing flow.
108
108
 
109
- ```text
110
- $archive <slug>
109
+ For CLI/runtime debugging only, the equivalent explicit sequence is:
110
+
111
+ ```bash
112
+ loopx approve <slug> --from review --to done
113
+ loopx archive <slug>
111
114
  ```
112
115
 
113
116
  This syncs the approved `.loopx/changes/active/<change-id>/spec-delta.md` into long-lived `.loopx/specs/` files and moves the change folder under `.loopx/changes/archive/<change-id>/`.
@@ -3,7 +3,7 @@ name: tdd
3
3
  description: "Guides feature and bugfix implementation through a failing test before production code and red-green-refactor discipline. Not for generated files or throwaway prototypes."
4
4
  when_to_use: "tdd, failing test first, feature implementation, bugfix, regression test, red green refactor, 测试先行"
5
5
  metadata:
6
- version: "0.1.7"
6
+ version: "0.1.9"
7
7
  ---
8
8
 
9
9
  # Test-Driven Development (TDD)
@@ -3,7 +3,7 @@ name: verify
3
3
  description: "Requires fresh verification evidence before claiming work is complete, fixed, passing, review-ready, or ready to commit. Not for speculative confidence or stale results."
4
4
  when_to_use: "verify, completion claim, fixed claim, tests pass, review-ready, commit, fresh evidence, 验证, 完成前检查"
5
5
  metadata:
6
- version: "0.1.7"
6
+ version: "0.1.9"
7
7
  ---
8
8
 
9
9
  # Verification Before Completion
@@ -40,6 +40,13 @@ function nextSkill(state) {
40
40
  && state.archive_status !== 'archived') {
41
41
  return `$archive ${state.slug}`;
42
42
  }
43
+ if (state.current_stage === 'review'
44
+ && state.review_verdict === 'approve'
45
+ && state.pending_user_decision === 'review->done'
46
+ && ['requested', 'approved'].includes(state.approval?.complete)
47
+ && state.archive_status !== 'archived') {
48
+ return `$archive ${state.slug}`;
49
+ }
43
50
  if (state.stage_status === 'awaiting-approval'
44
51
  && state.current_stage === 'plan'
45
52
  && Array.isArray(state.plan_blockers)
@@ -84,9 +91,6 @@ function nextSkill(state) {
84
91
  && state.approval?.rollback === 'approved') {
85
92
  return `$clarify ${state.slug}`;
86
93
  }
87
- if (state.current_stage === 'review' && state.review_verdict === 'approve' && state.pending_user_decision === 'review->done') {
88
- return `loopx approve ${state.slug} --from review --to done`;
89
- }
90
94
  return null;
91
95
  }
92
96
 
@@ -3,7 +3,7 @@ name: archive
3
3
  description: "Archives an approved loopx change delta into long-lived specs and writes an ADR candidate after done approval. Not for active builds or unapproved reviews."
4
4
  when_to_use: "archive, done workflow, spec delta, long-lived specs, ADR candidate, review approved, 归档, 同步规格"
5
5
  metadata:
6
- version: "0.1.7"
6
+ version: "0.1.9"
7
7
  argument-hint: "<workflow slug>"
8
8
  ---
9
9
 
@@ -3,7 +3,7 @@ name: autopilot
3
3
  description: "Runs one bounded autonomous loopx orchestration over clarify, plan, build, and review while preserving canonical artifacts. Not for manual gate-by-gate control."
4
4
  when_to_use: "autopilot, autonomous loopx run, end-to-end workflow, run all stages, bounded orchestration, 自动执行, 全流程"
5
5
  metadata:
6
- version: "0.1.7"
6
+ version: "0.1.9"
7
7
  argument-hint: "<workflow slug>"
8
8
  ---
9
9
 
@@ -3,7 +3,7 @@ name: build
3
3
  description: "Executes an approved loopx plan or review rework contract with evidence, verification, deslop, and regression gates. Not for unclear requirements or independent review."
4
4
  when_to_use: "build, implement approved plan, execute PRD, --from-review, review rework, implementation fixes, 执行, 实现, 修改"
5
5
  metadata:
6
- version: "0.1.7"
6
+ version: "0.1.9"
7
7
  argument-hint: "[--no-deslop] <approved PRD path or workflow slug> | --from-review <review artifact path>"
8
8
  ---
9
9
 
@@ -3,7 +3,7 @@ name: clarify
3
3
  description: "Clarifies ambiguous loopx work into requirements, non-goals, decision boundaries, and design-ready specs before planning. Not for already-approved plans or concrete implementation tasks."
4
4
  when_to_use: "clarify, requirements, ambiguous request, unclear scope, non-goals, decision boundaries, acceptance criteria, 需求澄清, 范围不清"
5
5
  metadata:
6
- version: "0.1.7"
6
+ version: "0.1.9"
7
7
  ---
8
8
 
9
9
  # loopx Clarify
@@ -3,7 +3,7 @@ name: debug
3
3
  description: "Finds root cause for bugs, failing tests, build failures, regressions, and unexpected behavior before fixes. Not for new feature planning or routine code review."
4
4
  when_to_use: "debug, bug, test failure, build failure, regression, unexpected behavior, root cause, 报错, 失败, 回归, 排查"
5
5
  metadata:
6
- version: "0.1.7"
6
+ version: "0.1.9"
7
7
  ---
8
8
 
9
9
  # Systematic Debugging
@@ -3,7 +3,7 @@ name: go-style
3
3
  description: "Applies loopx Go coding style for .go edits, tests, errors, context, naming, and interface boundaries. Not for non-Go code or Kratos-specific architecture by itself."
4
4
  when_to_use: "go-style, Go, golang, .go files, go tests, gofmt, idiomatic Go, Go style, Go 代码"
5
5
  metadata:
6
- version: "0.1.7"
6
+ version: "0.1.9"
7
7
  ---
8
8
 
9
9
  # Go Style
@@ -3,7 +3,7 @@ name: kratos
3
3
  description: "Supports Go-Kratos microservices, proto/buf APIs, service/biz/data layers, middleware, auth, config, and troubleshooting. Not for generic Go style alone."
4
4
  when_to_use: "kratos, Go-Kratos, proto, buf, service layer, biz layer, data layer, middleware, auth, config, Kratos 微服务"
5
5
  metadata:
6
- version: "0.1.7"
6
+ version: "0.1.9"
7
7
  ---
8
8
 
9
9
  # Kratos
@@ -3,7 +3,7 @@ name: plan
3
3
  description: "Creates a consensus-first loopx plan package with Planner, Architect, and Critic review from an approved spec. Not for unresolved requirements or direct implementation."
4
4
  when_to_use: "plan, planning, consensus planning, PRD, architecture plan, test plan, approved clarify spec, 规划, 方案, 架构评审"
5
5
  metadata:
6
- version: "0.1.7"
6
+ version: "0.1.9"
7
7
  argument-hint: "[--interactive] [--deliberate] [--direct <spec-path>] <clarified task or spec path>"
8
8
  ---
9
9
 
@@ -3,7 +3,7 @@ name: review
3
3
  description: "Reviews a loopx build execution record for acceptance, code risks, evidence quality, and architecture smells. Not for doing implementation work or replanning."
4
4
  when_to_use: "review, code review, acceptance, go no-go, execution-record, architecture smell, build complete, 审查, 验收"
5
5
  metadata:
6
- version: "0.1.7"
6
+ version: "0.1.9"
7
7
  argument-hint: "<execution-record path or workflow slug>"
8
8
  ---
9
9
 
@@ -101,13 +101,16 @@ For approval:
101
101
 
102
102
  ```text
103
103
  Next:
104
- loopx approve <slug> --from review --to done
104
+ $archive <slug>
105
105
  ```
106
106
 
107
- After the workflow reaches `done`, run:
107
+ `$archive` consumes the pending `review -> done` completion transition before syncing specs. Do not ask the user to run a separate `loopx approve <slug> --from review --to done` command in the normal Codex-facing flow.
108
108
 
109
- ```text
110
- $archive <slug>
109
+ For CLI/runtime debugging only, the equivalent explicit sequence is:
110
+
111
+ ```bash
112
+ loopx approve <slug> --from review --to done
113
+ loopx archive <slug>
111
114
  ```
112
115
 
113
116
  This syncs the approved `.loopx/changes/active/<change-id>/spec-delta.md` into long-lived `.loopx/specs/` files and moves the change folder under `.loopx/changes/archive/<change-id>/`.
@@ -3,7 +3,7 @@ name: tdd
3
3
  description: "Guides feature and bugfix implementation through a failing test before production code and red-green-refactor discipline. Not for generated files or throwaway prototypes."
4
4
  when_to_use: "tdd, failing test first, feature implementation, bugfix, regression test, red green refactor, 测试先行"
5
5
  metadata:
6
- version: "0.1.7"
6
+ version: "0.1.9"
7
7
  ---
8
8
 
9
9
  # Test-Driven Development (TDD)
@@ -3,7 +3,7 @@ name: verify
3
3
  description: "Requires fresh verification evidence before claiming work is complete, fixed, passing, review-ready, or ready to commit. Not for speculative confidence or stale results."
4
4
  when_to_use: "verify, completion claim, fixed claim, tests pass, review-ready, commit, fresh evidence, 验证, 完成前检查"
5
5
  metadata:
6
- version: "0.1.7"
6
+ version: "0.1.9"
7
7
  ---
8
8
 
9
9
  # Verification Before Completion
package/src/cli.mjs CHANGED
@@ -1,5 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ import { readFileSync } from 'node:fs';
4
+
3
5
  import { archiveStage, autopilotStage, approveStage, buildStage, clarifyStage, initWorkspace, planStage, reviewStage, statusSummary } from './workflow.mjs';
4
6
  import { renderHtmlViews } from './html-views.mjs';
5
7
  import { installBundledSkills } from './install-discovery.mjs';
@@ -7,9 +9,12 @@ import { nextSkillCommand, withNextSkill } from './next-skill.mjs';
7
9
  import { doctorRuntime, migrateLegacyRuntime } from './runtime-maintenance.mjs';
8
10
  import { setupWorkspaceContext } from './workspace-context.mjs';
9
11
 
12
+ const packageJson = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
13
+
10
14
  function usage() {
11
15
  return [
12
16
  'Usage:',
17
+ ' loopx --version',
13
18
  ' loopx init [--slug <slug>]',
14
19
  ' loopx clarify <slug> [--standard|--deep]',
15
20
  ' loopx approve <slug> --from <stage> --to <stage>',
@@ -139,6 +144,10 @@ function printHumanStatus(status) {
139
144
 
140
145
  async function main() {
141
146
  const { command, positionals, options } = parseArgs(process.argv.slice(2));
147
+ if (command === 'version' || command === '--version' || command === '-v') {
148
+ console.log(packageJson.version);
149
+ return;
150
+ }
142
151
  if (!command || command === 'help' || command === '--help' || command === '-h') {
143
152
  console.log(usage());
144
153
  return;
@@ -11,13 +11,14 @@ const WORKFLOW_ARTIFACTS = [
11
11
  { name: 'architecture.md', label: '架构', page: 'plan.html' },
12
12
  { name: 'development-plan.md', label: '开发计划', page: 'plan.html' },
13
13
  { name: 'test-plan.md', label: '测试计划', page: 'plan.html' },
14
+ { name: 'requirement-traceability.md', label: '需求覆盖矩阵', page: 'plan.html' },
14
15
  { name: 'execution-record.md', label: '执行记录', page: 'build.html' },
15
16
  { name: 'review-report.md', label: '评审报告', page: 'review.html' },
16
17
  ];
17
18
 
18
19
  const PAGE_GROUPS = [
19
20
  { file: 'intake.html', title: '需求澄清', artifacts: ['spec.md'] },
20
- { file: 'plan.html', title: '计划与架构', artifacts: ['plan.md', 'architecture.md', 'development-plan.md', 'test-plan.md'] },
21
+ { file: 'plan.html', title: '计划与架构', artifacts: ['plan.md', 'architecture.md', 'development-plan.md', 'test-plan.md', 'requirement-traceability.md'] },
21
22
  { file: 'build.html', title: '执行与验证', artifacts: ['execution-record.md'] },
22
23
  { file: 'review.html', title: '评审结论', artifacts: ['review-report.md'] },
23
24
  ];
@@ -84,15 +85,43 @@ function markdownToHtml(markdown) {
84
85
  const html = [];
85
86
  let inCode = false;
86
87
  let listOpen = false;
88
+ let orderedListOpen = false;
87
89
 
88
90
  const closeList = () => {
89
91
  if (listOpen) {
90
92
  html.push('</ul>');
91
93
  listOpen = false;
92
94
  }
95
+ if (orderedListOpen) {
96
+ html.push('</ol>');
97
+ orderedListOpen = false;
98
+ }
99
+ };
100
+ const tableCells = (line) => line.split('|').slice(1, -1).map((cell) => cell.trim());
101
+ const isTableDelimiter = (line) => /^\s*\|?\s*:?-{3,}:?\s*(\|\s*:?-{3,}:?\s*)+\|?\s*$/.test(line);
102
+ const inlineMarkdown = (value) => escapeHtml(value)
103
+ .replace(/`([^`]+)`/g, '<code>$1</code>')
104
+ .replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>');
105
+ const renderTable = (start) => {
106
+ const header = tableCells(lines[start]);
107
+ const rows = [];
108
+ let index = start + 2;
109
+ while (index < lines.length && lines[index].trim().startsWith('|')) {
110
+ rows.push(tableCells(lines[index]));
111
+ index += 1;
112
+ }
113
+ html.push('<table>');
114
+ html.push(`<thead><tr>${header.map((cell) => `<th>${inlineMarkdown(cell)}</th>`).join('')}</tr></thead>`);
115
+ html.push('<tbody>');
116
+ for (const row of rows) {
117
+ html.push(`<tr>${header.map((_, cellIndex) => `<td>${inlineMarkdown(row[cellIndex] || '')}</td>`).join('')}</tr>`);
118
+ }
119
+ html.push('</tbody></table>');
120
+ return index - 1;
93
121
  };
94
122
 
95
- for (const line of lines) {
123
+ for (let index = 0; index < lines.length; index += 1) {
124
+ const line = lines[index];
96
125
  if (line.startsWith('```')) {
97
126
  if (inCode) {
98
127
  html.push('</code></pre>');
@@ -114,12 +143,33 @@ function markdownToHtml(markdown) {
114
143
  html.push(`<h${level}>${escapeHtml(line.replace(/^#{1,4}\s+/, ''))}</h${level}>`);
115
144
  continue;
116
145
  }
146
+ if (line.trim().startsWith('|') && lines[index + 1] && isTableDelimiter(lines[index + 1])) {
147
+ closeList();
148
+ index = renderTable(index);
149
+ continue;
150
+ }
117
151
  if (line.startsWith('- ')) {
152
+ if (orderedListOpen) {
153
+ html.push('</ol>');
154
+ orderedListOpen = false;
155
+ }
118
156
  if (!listOpen) {
119
157
  html.push('<ul>');
120
158
  listOpen = true;
121
159
  }
122
- html.push(`<li>${escapeHtml(line.slice(2))}</li>`);
160
+ html.push(`<li>${inlineMarkdown(line.slice(2))}</li>`);
161
+ continue;
162
+ }
163
+ if (/^\d+[.)]\s+/.test(line)) {
164
+ if (listOpen) {
165
+ html.push('</ul>');
166
+ listOpen = false;
167
+ }
168
+ if (!orderedListOpen) {
169
+ html.push('<ol>');
170
+ orderedListOpen = true;
171
+ }
172
+ html.push(`<li>${inlineMarkdown(line.replace(/^\d+[.)]\s+/, ''))}</li>`);
123
173
  continue;
124
174
  }
125
175
  if (!line.trim()) {
@@ -127,7 +177,7 @@ function markdownToHtml(markdown) {
127
177
  continue;
128
178
  }
129
179
  closeList();
130
- html.push(`<p>${escapeHtml(line)}</p>`);
180
+ html.push(`<p>${inlineMarkdown(line)}</p>`);
131
181
  }
132
182
  closeList();
133
183
  if (inCode) {
@@ -150,6 +200,7 @@ function statusPanels(status) {
150
200
  '<section class="grid">',
151
201
  `<div class="panel"><strong>阶段</strong><br>${escapeHtml(state.current_stage || '(none)')}</div>`,
152
202
  `<div class="panel"><strong>状态</strong><br>${escapeHtml(state.stage_status || '(unknown)')}</div>`,
203
+ `<div class="panel"><strong>需求覆盖</strong><br>${escapeHtml(state.source_requirements_status || 'unknown')}</div>`,
153
204
  `<div class="panel"><strong>下一步</strong><br><code>${escapeHtml(nextSkill || status.next_action || 'none')}</code></div>`,
154
205
  `<div class="panel"><strong>归档</strong><br>${escapeHtml(state.archive_status || 'pending')}</div>`,
155
206
  '</section>',
@@ -19,6 +19,13 @@ export function nextSkillCommand(state) {
19
19
  && state.archive_status !== 'archived') {
20
20
  return `$archive ${state.slug}`;
21
21
  }
22
+ if (state.current_stage === 'review'
23
+ && state.review_verdict === 'approve'
24
+ && state.pending_user_decision === 'review->done'
25
+ && ['requested', 'approved'].includes(state.approval?.complete)
26
+ && state.archive_status !== 'archived') {
27
+ return `$archive ${state.slug}`;
28
+ }
22
29
  if (state.stage_status !== 'awaiting-approval') {
23
30
  return null;
24
31
  }
package/src/workflow.mjs CHANGED
@@ -720,21 +720,21 @@ async function writeRequirementTraceabilityArtifact({ root, sourceSpecPath, sour
720
720
  const status = blockers.length > 0 ? 'partial' : 'complete';
721
721
 
722
722
  await writeText(traceabilityPath, [
723
- '# Source Requirements Traceability',
723
+ '# 原始需求覆盖矩阵',
724
724
  '',
725
- `- source: ${sourceSpecPath}`,
726
- `- status: ${status}`,
727
- `- extracted_items: ${rows.length}`,
725
+ `- 来源:${sourceSpecPath}`,
726
+ `- 状态:${status}`,
727
+ `- 提取项数量:${rows.length}`,
728
728
  '',
729
- '## Coverage Matrix',
729
+ '## 覆盖矩阵',
730
730
  '',
731
- '| Source requirement | Status |',
731
+ '| 原始需求项 | 覆盖状态 |',
732
732
  '| --- | --- |',
733
733
  ...(rows.length > 0
734
734
  ? rows.map((row) => `| ${row.item.replace(/\|/g, '\\|')} | ${row.status} |`)
735
- : ['| No explicit source coverage items detected | covered |']),
735
+ : ['| 未检测到显式需求覆盖项 | covered |']),
736
736
  '',
737
- '## Gate',
737
+ '## 门禁',
738
738
  '',
739
739
  ...(blockers.length > 0
740
740
  ? blockers.map((blocker) => `- ${blocker}`)
@@ -2248,7 +2248,7 @@ function buildCurrentEvidenceChain(state, readiness = buildReadiness(state), aut
2248
2248
  evidence.push(evidenceEntry(
2249
2249
  'review_approved',
2250
2250
  'Review verdict is approve.',
2251
- authorization.done.authorized ? 'The approved review -> done transition can be consumed.' : 'Completion still requires explicit review -> done authorization.',
2251
+ authorization.done.authorized ? 'Archive can consume the approved review -> done transition before syncing specs.' : 'Completion still requires explicit review -> done authorization.',
2252
2252
  ));
2253
2253
  }
2254
2254
  if (state.archive_status === 'archived' && state.spec_sync_status === 'synced') {
@@ -2371,9 +2371,7 @@ function recommendedAction(state, legacy = false) {
2371
2371
  : 'Approve build -> review when execution-record.md is complete.';
2372
2372
  case STAGES.REVIEW:
2373
2373
  if (state.review_verdict === 'approve') {
2374
- return state.approval.complete === APPROVAL_STATES.APPROVED
2375
- ? 'Run loopx review again to consume the approved review -> done transition.'
2376
- : 'Approve review -> done to complete the workflow.';
2374
+ return 'Run loopx archive; archive consumes the pending review -> done completion transition before syncing specs.';
2377
2375
  }
2378
2376
  if (state.review_verdict === 'request-changes') {
2379
2377
  if (state.requested_transition === TRANSITIONS.REVIEW_TO_BUILD && state.approval.build === APPROVAL_STATES.APPROVED) {
@@ -2574,7 +2572,11 @@ function nextCommandForRollbackTarget(slug, target) {
2574
2572
  if (target === 'none') {
2575
2573
  return [
2576
2574
  'Next:',
2575
+ `$archive ${slug}`,
2576
+ '',
2577
+ 'CLI-only equivalent:',
2577
2578
  `loopx approve ${slug} --from review --to done`,
2579
+ `loopx archive ${slug}`,
2578
2580
  ].join('\n');
2579
2581
  }
2580
2582
  return [
@@ -2587,7 +2589,7 @@ function nextCommandForRollbackTarget(slug, target) {
2587
2589
  function reviewUserMessageZh({ slug, verdict, rollbackTarget, findings }) {
2588
2590
  const label = reviewVerdictLabel(verdict);
2589
2591
  const next = verdict === 'APPROVE'
2590
- ? `下一步:批准 review -> done 后完成工作流。\n${nextCommandForRollbackTarget(slug, 'none')}`
2592
+ ? `下一步:直接归档;archive 会先消费 pending 的 review -> done 完成态。\n${nextCommandForRollbackTarget(slug, 'none')}`
2591
2593
  : `下一步:按审查发现处理,并${rollbackTargetLabel(rollbackTarget)}。\n${nextCommandForRollbackTarget(slug, rollbackTarget)}`;
2592
2594
  const findingText = Array.isArray(findings) && findings.length > 0 ? findings.join(';') : '无额外发现。';
2593
2595
  return `Review 结果:${slug} ${label}。审查发现:${findingText} ${next}`;
@@ -3929,7 +3931,7 @@ export async function reviewStage(cwd, slug, { reviewer = 'independent-reviewer'
3929
3931
  verdict: reviewInput.verdict,
3930
3932
  reviewMessageZh: reviewMessage,
3931
3933
  evidenceManifest: reviewInput.evidenceManifest,
3932
- followUps: ['等待 review -> done 审批。'],
3934
+ followUps: ['执行 $archive;archive 会消费 pending 的 review -> done 完成态。'],
3933
3935
  });
3934
3936
  } catch (error) {
3935
3937
  journalWarning = error instanceof Error ? error.message : String(error);