sdd-forge 0.1.0-alpha.549 → 0.1.0-alpha.622

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 (149) hide show
  1. package/README.md +1 -1
  2. package/package.json +1 -1
  3. package/src/AGENTS.md +1 -1
  4. package/src/docs/commands/agents.js +2 -2
  5. package/src/docs/commands/enrich.js +1 -1
  6. package/src/docs/commands/forge.js +5 -19
  7. package/src/docs/commands/readme.js +2 -2
  8. package/src/docs/commands/text.js +1 -2
  9. package/src/docs/commands/translate.js +2 -3
  10. package/src/flow/commands/merge.js +23 -22
  11. package/src/flow/commands/report.js +11 -11
  12. package/src/flow/commands/review.js +368 -50
  13. package/src/flow/lib/base-command.js +40 -0
  14. package/src/flow/lib/get-check.js +84 -0
  15. package/src/flow/{get/context.js → lib/get-context.js} +64 -151
  16. package/src/flow/lib/get-guardrail.js +61 -0
  17. package/src/flow/lib/get-issue.js +42 -0
  18. package/src/flow/{get/prompt.js → lib/get-prompt.js} +40 -39
  19. package/src/flow/lib/get-qa-count.js +16 -0
  20. package/src/flow/lib/get-resolve-context.js +99 -0
  21. package/src/flow/lib/get-status.js +38 -0
  22. package/src/flow/lib/phases.js +15 -0
  23. package/src/flow/lib/run-finalize.js +337 -0
  24. package/src/flow/lib/run-gate.js +463 -0
  25. package/src/flow/lib/run-impl-confirm.js +97 -0
  26. package/src/flow/lib/run-lint.js +61 -0
  27. package/src/flow/lib/run-prepare-spec.js +324 -0
  28. package/src/flow/lib/run-report.js +56 -0
  29. package/src/flow/lib/run-resume.js +103 -0
  30. package/src/flow/lib/run-retro.js +232 -0
  31. package/src/flow/lib/run-review.js +196 -0
  32. package/src/flow/lib/run-sync.js +85 -0
  33. package/src/flow/lib/set-auto.js +28 -0
  34. package/src/flow/lib/set-issue-log.js +73 -0
  35. package/src/flow/lib/set-issue.js +29 -0
  36. package/src/flow/lib/set-metric.js +42 -0
  37. package/src/flow/lib/set-note.js +24 -0
  38. package/src/flow/lib/set-req.js +30 -0
  39. package/src/flow/lib/set-request.js +24 -0
  40. package/src/flow/lib/set-step.js +25 -0
  41. package/src/flow/lib/set-summary.js +35 -0
  42. package/src/flow/lib/set-test-summary.js +39 -0
  43. package/src/flow/registry.js +298 -40
  44. package/src/flow.js +92 -22
  45. package/src/lib/agent.js +8 -4
  46. package/src/lib/cli.js +9 -15
  47. package/src/lib/flow-state.js +97 -61
  48. package/src/lib/git-helpers.js +70 -0
  49. package/src/lib/lint.js +2 -2
  50. package/src/lib/process.js +76 -21
  51. package/src/presets/api/templates/en/guardrail.json +25 -0
  52. package/src/presets/api/templates/ja/guardrail.json +25 -0
  53. package/src/presets/architecture/templates/en/guardrail.json +15 -0
  54. package/src/presets/architecture/templates/ja/guardrail.json +15 -0
  55. package/src/presets/base/templates/en/guardrail.json +64 -1
  56. package/src/presets/base/templates/ja/guardrail.json +64 -1
  57. package/src/presets/cakephp2/data/models.js +101 -103
  58. package/src/presets/ci/preset.json +1 -9
  59. package/src/presets/ci/templates/en/ci_cd.md +12 -6
  60. package/src/presets/ci/templates/en/guardrail.json +25 -0
  61. package/src/presets/ci/templates/ja/ci_cd.md +12 -6
  62. package/src/presets/ci/templates/ja/guardrail.json +25 -0
  63. package/src/presets/cli/templates/en/guardrail.json +0 -11
  64. package/src/presets/cli/templates/ja/guardrail.json +0 -11
  65. package/src/presets/coding-rule/preset.json +5 -0
  66. package/src/presets/coding-rule/templates/en/guardrail.json +51 -0
  67. package/src/presets/coding-rule/templates/ja/guardrail.json +51 -0
  68. package/src/presets/database/templates/en/guardrail.json +58 -0
  69. package/src/presets/database/templates/ja/guardrail.json +58 -0
  70. package/src/presets/document/preset.json +5 -0
  71. package/src/presets/document/templates/en/guardrail.json +24 -0
  72. package/src/presets/document/templates/ja/guardrail.json +24 -0
  73. package/src/presets/edge/templates/en/guardrail.json +35 -0
  74. package/src/presets/edge/templates/ja/guardrail.json +35 -0
  75. package/src/presets/{ci → github-actions}/data/pipelines.js +1 -1
  76. package/src/presets/github-actions/preset.json +11 -0
  77. package/src/presets/github-actions/templates/en/ci_cd.md +16 -0
  78. package/src/presets/github-actions/templates/en/guardrail.json +34 -0
  79. package/src/presets/github-actions/templates/ja/ci_cd.md +16 -0
  80. package/src/presets/github-actions/templates/ja/guardrail.json +34 -0
  81. package/src/presets/graphql/templates/en/guardrail.json +36 -0
  82. package/src/presets/graphql/templates/ja/guardrail.json +36 -0
  83. package/src/presets/greenfield/preset.json +5 -0
  84. package/src/presets/greenfield/templates/en/guardrail.json +65 -0
  85. package/src/presets/greenfield/templates/ja/guardrail.json +65 -0
  86. package/src/presets/infrastructure/preset.json +5 -0
  87. package/src/presets/infrastructure/templates/en/guardrail.json +15 -0
  88. package/src/presets/infrastructure/templates/ja/guardrail.json +15 -0
  89. package/src/presets/js-webapp/templates/en/guardrail.json +14 -0
  90. package/src/presets/js-webapp/templates/ja/guardrail.json +14 -0
  91. package/src/presets/laravel/data/controllers.js +71 -88
  92. package/src/presets/laravel/data/models.js +148 -172
  93. package/src/presets/library/templates/en/guardrail.json +10 -0
  94. package/src/presets/library/templates/ja/guardrail.json +10 -0
  95. package/src/presets/maintenance/preset.json +5 -0
  96. package/src/presets/maintenance/templates/en/guardrail.json +45 -0
  97. package/src/presets/maintenance/templates/ja/guardrail.json +45 -0
  98. package/src/presets/monorepo/templates/en/guardrail.json +26 -0
  99. package/src/presets/monorepo/templates/ja/guardrail.json +26 -0
  100. package/src/presets/nextjs/templates/en/guardrail.json +36 -0
  101. package/src/presets/nextjs/templates/ja/guardrail.json +36 -0
  102. package/src/presets/oss-contribute/preset.json +5 -0
  103. package/src/presets/oss-contribute/templates/en/guardrail.json +35 -0
  104. package/src/presets/oss-contribute/templates/ja/guardrail.json +35 -0
  105. package/src/presets/rest/templates/en/guardrail.json +15 -0
  106. package/src/presets/rest/templates/ja/guardrail.json +15 -0
  107. package/src/presets/storage/templates/en/guardrail.json +26 -0
  108. package/src/presets/storage/templates/ja/guardrail.json +26 -0
  109. package/src/presets/symfony/NOTICE +51 -0
  110. package/src/presets/symfony/data/controllers.js +77 -103
  111. package/src/presets/symfony/data/entities.js +111 -107
  112. package/src/presets/symfony/templates/en/guardrail.json +279 -18
  113. package/src/presets/symfony/templates/ja/guardrail.json +276 -15
  114. package/src/presets/ui-ux/preset.json +5 -0
  115. package/src/presets/web-design/preset.json +1 -1
  116. package/src/presets/webapp/templates/en/guardrail.json +46 -14
  117. package/src/presets/webapp/templates/ja/guardrail.json +46 -14
  118. package/src/presets/workers/templates/en/guardrail.json +15 -0
  119. package/src/presets/workers/templates/ja/guardrail.json +15 -0
  120. package/src/templates/partials/{redo-recording.md → issue-log-recording.md} +5 -5
  121. package/src/templates/skills/sdd-forge.flow-finalize/SKILL.md +4 -3
  122. package/src/templates/skills/sdd-forge.flow-impl/SKILL.md +26 -7
  123. package/src/templates/skills/sdd-forge.flow-plan/SKILL.md +64 -20
  124. package/src/flow/get/check.js +0 -97
  125. package/src/flow/get/guardrail.js +0 -76
  126. package/src/flow/get/issue.js +0 -38
  127. package/src/flow/get/qa-count.js +0 -21
  128. package/src/flow/get/resolve-context.js +0 -133
  129. package/src/flow/get/status.js +0 -42
  130. package/src/flow/run/finalize.js +0 -292
  131. package/src/flow/run/gate.js +0 -252
  132. package/src/flow/run/impl-confirm.js +0 -121
  133. package/src/flow/run/lint.js +0 -79
  134. package/src/flow/run/prepare-spec.js +0 -339
  135. package/src/flow/run/report.js +0 -91
  136. package/src/flow/run/retro.js +0 -269
  137. package/src/flow/run/review.js +0 -130
  138. package/src/flow/run/sync.js +0 -114
  139. package/src/flow/set/auto.js +0 -29
  140. package/src/flow/set/issue.js +0 -33
  141. package/src/flow/set/metric.js +0 -48
  142. package/src/flow/set/note.js +0 -27
  143. package/src/flow/set/redo.js +0 -113
  144. package/src/flow/set/req.js +0 -34
  145. package/src/flow/set/request.js +0 -27
  146. package/src/flow/set/step.js +0 -28
  147. package/src/flow/set/summary.js +0 -40
  148. package/src/flow/set/test-summary.js +0 -57
  149. package/src/lib/git-state.js +0 -52
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # <!-- {{data("cli.project.name")}} -->sdd-forge<!-- {{/data}} -->
2
2
 
3
3
  <!-- {{data("cli.docs.langSwitcher", {labels: "absolute"})}} -->
4
- **English** | [日本語](https://github.com/SpreadWorks/sdd-forge/blob/main/docs/ja/README.md)
4
+ [日本語](https://github.com/SpreadWorks/sdd-forge/blob/main/docs/ja/README.md) | **English**
5
5
  <!-- {{/data}} -->
6
6
 
7
7
  [![npm version](https://img.shields.io/npm/v/sdd-forge.svg)](https://www.npmjs.com/package/sdd-forge)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sdd-forge",
3
- "version": "0.1.0-alpha.549",
3
+ "version": "0.1.0-alpha.622",
4
4
  "description": "Spec-Driven Development tooling for automated documentation generation",
5
5
  "repository": {
6
6
  "type": "git",
package/src/AGENTS.md CHANGED
@@ -27,7 +27,7 @@ src/
27
27
  │ ├── presets.js プリセット自動探索・親チェーン解決
28
28
  │ ├── flow-state.js SDD フロー状態永続化
29
29
  │ ├── flow-envelope.js flow get/set/run の JSON envelope
30
- │ ├── git-state.js git/gh 状態取得ヘルパー
30
+ │ ├── git-helpers.js git/gh 状態取得ヘルパー
31
31
  │ ├── include.js include ディレクティブ展開
32
32
  │ ├── i18n.js 3層 i18n(ドメイン名前空間付き)
33
33
  │ └── types.js 型エイリアス解決・バリデーション
@@ -12,7 +12,7 @@ import path from "path";
12
12
  import { runIfDirect } from "../../lib/entrypoint.js";
13
13
  import { parseArgs } from "../../lib/cli.js";
14
14
  import { sddOutputDir } from "../../lib/config.js";
15
- import { callAgent, loadAgentConfig, DEFAULT_AGENT_TIMEOUT_MS } from "../../lib/agent.js";
15
+ import { callAgent, loadAgentConfig } from "../../lib/agent.js";
16
16
  import { translate } from "../../lib/i18n.js";
17
17
  import { createResolver } from "../lib/resolver-factory.js";
18
18
  import { createLogger } from "../../lib/progress.js";
@@ -201,7 +201,7 @@ async function main(ctx) {
201
201
  const prompt = buildRefinePrompt(projectContent, combinedDocs, config, srcRoot, sddContent);
202
202
 
203
203
  try {
204
- const result = callAgent(agent, prompt, DEFAULT_AGENT_TIMEOUT_MS, undefined, { systemPrompt });
204
+ const result = callAgent(agent, prompt, agent.timeoutMs, undefined, { systemPrompt });
205
205
 
206
206
  let refined = result.trim();
207
207
 
@@ -441,7 +441,7 @@ async function main(ctx) {
441
441
  const batches = splitIntoBatches(pending, maxTokens);
442
442
  const concurrency = resolveConcurrency(config);
443
443
 
444
- const timeoutMs = config.agent?.timeout ? Number(config.agent.timeout) * 1000 : DEFAULT_AGENT_TIMEOUT_MS;
444
+ const timeoutMs = agent.timeoutMs || DEFAULT_AGENT_TIMEOUT_MS;
445
445
  let totalEnriched = 0;
446
446
 
447
447
  logger.log(`${batches.length} batches (token limit: ${maxTokens}, concurrency: ${concurrency})`);
@@ -13,7 +13,7 @@
13
13
 
14
14
  import fs from "fs";
15
15
  import path from "path";
16
- import { execFile } from "child_process";
16
+ import { runCmdAsync } from "../../lib/process.js";
17
17
  import { runIfDirect } from "../../lib/entrypoint.js";
18
18
  import { populateFromAnalysis } from "./data.js";
19
19
  import { textFillFromAnalysis } from "./text.js";
@@ -119,28 +119,14 @@ function printHelp() {
119
119
  }
120
120
 
121
121
  /**
122
- * コマンド文字列をコマンドと引数に分割して execFile で実行する。
122
+ * コマンド文字列をコマンドと引数に分割して実行する。
123
123
  * bash に依存しない。
124
124
  */
125
125
  function runCommand(cmdString, cwd) {
126
126
  const parts = cmdString.match(/"[^"]*"|'[^']*'|\S+/g) || [];
127
127
  const command = parts[0];
128
128
  const args = parts.slice(1).map((s) => s.replace(/^["']|["']$/g, ""));
129
- return new Promise((resolve) => {
130
- execFile(
131
- command,
132
- args,
133
- { cwd, maxBuffer: 20 * 1024 * 1024 },
134
- (err, stdout, stderr) => {
135
- resolve({
136
- ok: !err,
137
- code: err?.code ?? 0,
138
- stdout: String(stdout || ""),
139
- stderr: String(stderr || ""),
140
- });
141
- }
142
- );
143
- });
129
+ return runCmdAsync(command, args, { cwd });
144
130
  }
145
131
 
146
132
  /**
@@ -220,7 +206,7 @@ async function main() {
220
206
  const t = translate();
221
207
  const agent = resolveAgent(config, "docs.forge");
222
208
  const mode = cli.mode || DEFAULT_MODE;
223
- const timeoutMs = config.agent?.timeout ? Number(config.agent.timeout) * 1000 : undefined;
209
+ const timeoutMs = agent?.timeoutMs;
224
210
 
225
211
  if (mode === "agent" && !agent) {
226
212
  throw new Error(
@@ -397,7 +383,7 @@ async function main() {
397
383
  // docs/ を直接編集するため generate ステップは不要
398
384
 
399
385
  const review = await runCommand(cli.reviewCmd, root);
400
- console.log(`[forge] review: ${review.ok ? "ok" : "failed"} (code=${review.code})`);
386
+ console.log(`[forge] review: ${review.ok ? "ok" : "failed"} (code=${review.status})`);
401
387
  if (review.ok) {
402
388
  console.log("[forge] review passed.");
403
389
  const readme = await runCommand(`node "${path.join(PKG_DIR, "docs", "commands", "readme.js")}"`, root);
@@ -21,7 +21,7 @@ import { resolveCommandContext, loadFullAnalysis } from "../lib/command-context.
21
21
  import { processTemplate } from "./text.js";
22
22
  import { buildTextSystemPrompt } from "../lib/text-prompts.js";
23
23
  import { loadConfig, resolveConcurrency } from "../../lib/config.js";
24
- import { loadAgentConfig, ensureAgentWorkDir, DEFAULT_AGENT_TIMEOUT_MS } from "../../lib/agent.js";
24
+ import { loadAgentConfig, ensureAgentWorkDir } from "../../lib/agent.js";
25
25
 
26
26
  const logger = createLogger("readme");
27
27
 
@@ -148,7 +148,7 @@ async function main(ctx) {
148
148
  const analysis = loadFullAnalysis(root) || {};
149
149
  const documentStyle = cfg.docs?.style;
150
150
  const systemPrompt = buildTextSystemPrompt(documentStyle, lang);
151
- const timeoutMs = DEFAULT_AGENT_TIMEOUT_MS;
151
+ const timeoutMs = agent.timeoutMs;
152
152
 
153
153
  const result = await processTemplate(
154
154
  resolved, analysis, "README.md", agent, timeoutMs,
@@ -687,11 +687,10 @@ async function main(ctx) {
687
687
  logger.verbose(`--id=${ctx.id}: per-directive mode forced.`);
688
688
  }
689
689
 
690
- const configTimeout = cfg.agent?.timeout ? Number(cfg.agent.timeout) * 1000 : undefined;
691
690
  const retryCount = Number(cfg?.agent?.retryCount) || 0;
692
691
  const processFn = ctx.perDirective ? processTemplate : processTemplateFileBatch;
693
692
  if (!ctx.perDirective) {
694
- if (!ctx.timeout) ctx.timeout = configTimeout || DEFAULT_TIMEOUT_MS;
693
+ if (!ctx.timeout) ctx.timeout = agent.timeoutMs || DEFAULT_TIMEOUT_MS;
695
694
  logger.verbose(`Mode: batch (file-level, ${targetFiles.length} file(s), concurrency=${concurrency}, timeout=${ctx.timeout}ms). Use --per-directive for single-call mode.`);
696
695
  }
697
696
 
@@ -15,13 +15,12 @@ import { runIfDirect } from "../../lib/entrypoint.js";
15
15
  import { parseArgs } from "../../lib/cli.js";
16
16
  import { resolveOutputConfig } from "../../lib/types.js";
17
17
  import { resolveConcurrency } from "../../lib/config.js";
18
- import { callAgentAsync, DEFAULT_AGENT_TIMEOUT_MS } from "../../lib/agent.js";
18
+ import { callAgentAsync } from "../../lib/agent.js";
19
19
  import { createLogger } from "../../lib/progress.js";
20
20
  import { resolveCommandContext, getChapterFiles, stripResponsePreamble } from "../lib/command-context.js";
21
21
  import { mapWithConcurrency } from "../lib/concurrency.js";
22
22
 
23
23
  const logger = createLogger("translate");
24
- const DEFAULT_TIMEOUT_MS = DEFAULT_AGENT_TIMEOUT_MS;
25
24
 
26
25
  /**
27
26
  * Translate a Markdown document from one language to another via AI agent.
@@ -72,7 +71,7 @@ async function translateDocument(content, fromLang, toLang, agent, root, documen
72
71
 
73
72
  const prompt = content;
74
73
 
75
- const result = await callAgentAsync(agent, prompt, DEFAULT_TIMEOUT_MS, root, {
74
+ const result = await callAgentAsync(agent, prompt, agent.timeoutMs, root, {
76
75
  systemPrompt,
77
76
  });
78
77
 
@@ -5,10 +5,11 @@
5
5
  * Called by finalize.js with ctx containing root, flowState, worktreePath, mainRepoPath, mergeStrategy.
6
6
  */
7
7
 
8
- import { execFileSync } from "child_process";
9
8
  import { readFileSync } from "fs";
9
+ import { runCmd } from "../../lib/process.js";
10
10
  import path from "path";
11
11
  import { loadConfig } from "../../lib/config.js";
12
+ import { isGhAvailable } from "../../lib/git-helpers.js";
12
13
 
13
14
  /**
14
15
  * Resolve push remote from config.
@@ -19,19 +20,6 @@ function resolveRemote(cfg) {
19
20
  return cfg?.flow?.push?.remote || "origin";
20
21
  }
21
22
 
22
- /**
23
- * Check if gh command is available.
24
- * @returns {boolean}
25
- */
26
- function isGhAvailable() {
27
- try {
28
- execFileSync("gh", ["--version"], { stdio: "ignore" });
29
- return true;
30
- } catch (_) {
31
- return false;
32
- }
33
- }
34
-
35
23
  /**
36
24
  * Extract a markdown section body by heading name.
37
25
  * @param {string} content - full markdown text
@@ -177,14 +165,16 @@ function main(ctx) {
177
165
  const title = buildPrTitle(spec, fallbackTitle);
178
166
  const body = buildPrBody(state, spec);
179
167
 
180
- execFileSync("git", ["push", "-u", remote, featureBranch], { stdio: "inherit" });
181
- execFileSync("gh", [
168
+ const pushRes = runCmd("git", ["push", "-u", remote, featureBranch]);
169
+ if (!pushRes.ok) throw new Error(pushRes.stderr || "git push failed");
170
+ const prRes = runCmd("gh", [
182
171
  "pr", "create",
183
172
  "--base", baseBranch,
184
173
  "--head", featureBranch,
185
174
  "--title", title,
186
175
  ...(body ? ["--body", body] : []),
187
- ], { stdio: "inherit" });
176
+ ]);
177
+ if (!prRes.ok) throw new Error(prRes.stderr || "gh pr create failed");
188
178
  return { strategy: "pr" };
189
179
  }
190
180
 
@@ -192,16 +182,27 @@ function main(ctx) {
192
182
  const specTitle = state.spec?.replace(/^specs\/\d+-/, "").replace(/\/spec\.md$/, "") || featureBranch;
193
183
  const commitMsg = state.issue ? `${specTitle}\n\nfixes #${state.issue}` : specTitle;
194
184
 
185
+ function runSquashMerge(gitPrefix, hint) {
186
+ const mergeArgs = [...gitPrefix, "merge", "--squash", featureBranch];
187
+ const resetArgs = [...gitPrefix, "reset", "--merge"];
188
+ const mergeRes = runCmd("git", mergeArgs);
189
+ if (!mergeRes.ok) {
190
+ runCmd("git", resetArgs);
191
+ throw new Error(`Merge conflict detected. ${hint}`);
192
+ }
193
+ const commitRes = runCmd("git", [...gitPrefix, "commit", "-m", commitMsg]);
194
+ if (!commitRes.ok) throw new Error(commitRes.stderr || "commit after squash merge failed");
195
+ }
196
+
195
197
  if (worktree && mainRepoPath) {
196
- execFileSync("git", ["-C", mainRepoPath, "merge", "--squash", featureBranch], { stdio: "inherit" });
197
- execFileSync("git", ["-C", mainRepoPath, "commit", "-m", commitMsg], { stdio: "inherit" });
198
+ runSquashMerge(["-C", mainRepoPath], `Run 'git rebase ${baseBranch}' in the worktree and retry finalize.`);
198
199
  return { strategy: "squash" };
199
200
  }
200
201
 
201
202
  // Branch mode
202
- execFileSync("git", ["checkout", baseBranch], { stdio: "inherit" });
203
- execFileSync("git", ["merge", "--squash", featureBranch], { stdio: "inherit" });
204
- execFileSync("git", ["commit", "-m", commitMsg], { stdio: "inherit" });
203
+ const checkoutRes = runCmd("git", ["checkout", baseBranch]);
204
+ if (!checkoutRes.ok) throw new Error(checkoutRes.stderr || "git checkout failed");
205
+ runSquashMerge([], `Run 'git rebase ${baseBranch}' and retry finalize.`);
205
206
  return { strategy: "squash" };
206
207
  }
207
208
 
@@ -7,7 +7,7 @@
7
7
 
8
8
  import fs from "fs";
9
9
  import path from "path";
10
- import { loadRedoLog } from "../set/redo.js";
10
+ import { loadIssueLog } from "../lib/set-issue-log.js";
11
11
 
12
12
  /**
13
13
  * Aggregate metrics across all phases.
@@ -15,7 +15,7 @@ import { loadRedoLog } from "../set/redo.js";
15
15
  * @returns {{ docsRead: number, srcRead: number, question: number, redo: number }}
16
16
  */
17
17
  function aggregateMetrics(metrics) {
18
- const totals = { docsRead: 0, srcRead: 0, question: 0, redo: 0 };
18
+ const totals = { docsRead: 0, srcRead: 0, question: 0, issueLog: 0 };
19
19
  if (!metrics) return totals;
20
20
  for (const phase of Object.values(metrics)) {
21
21
  if (!phase || typeof phase !== "object") continue;
@@ -31,13 +31,13 @@ function aggregateMetrics(metrics) {
31
31
  * @param {Object} input
32
32
  * @param {Object} input.state - flow.json state
33
33
  * @param {Object} input.results - finalize step results
34
- * @param {Object} input.redolog - redolog data { entries: [] }
34
+ * @param {Object} input.issueLog - issue-log data { entries: [] }
35
35
  * @param {string} input.implDiffStat - git diff --stat output for implementation
36
36
  * @param {string[]} input.commitMessages - commit messages from feature branch
37
37
  * @returns {{ data: Object, text: string }}
38
38
  */
39
39
  export function generateReport(input) {
40
- const { state, results, redolog, implDiffStat, commitMessages } = input;
40
+ const { state, results, issueLog, implDiffStat, commitMessages } = input;
41
41
 
42
42
  // Implementation
43
43
  const implementation = {
@@ -52,8 +52,8 @@ export function generateReport(input) {
52
52
  : null;
53
53
 
54
54
  // Redolog
55
- const entries = redolog?.entries || [];
56
- const redologData = {
55
+ const entries = issueLog?.entries || [];
56
+ const issueLogData = {
57
57
  count: entries.length,
58
58
  entries: entries.map(e => ({
59
59
  step: e.step,
@@ -96,7 +96,7 @@ export function generateReport(input) {
96
96
  tests = { unit, integration, acceptance, total: unit + integration + acceptance };
97
97
  }
98
98
 
99
- const data = { implementation, retro, redolog: redologData, metrics, tests, sync };
99
+ const data = { implementation, retro, issueLog: issueLogData, metrics, tests, sync };
100
100
  const text = formatText(data);
101
101
 
102
102
  return { data, text };
@@ -150,7 +150,7 @@ function formatText(data) {
150
150
  lines.push(" Metrics");
151
151
  lines.push(` ${thin}`);
152
152
  const m = data.metrics;
153
- lines.push(` docs ${m.docsRead} src ${m.srcRead} Q&A ${m.question} redo ${m.redo}`);
153
+ lines.push(` docs ${m.docsRead} src ${m.srcRead} Q&A ${m.question} issues ${m.issueLog}`);
154
154
 
155
155
  // Tests
156
156
  if (data.tests) {
@@ -162,11 +162,11 @@ function formatText(data) {
162
162
  }
163
163
 
164
164
  // Redo (only if entries exist)
165
- if (data.redolog.count > 0) {
165
+ if (data.issueLog.count > 0) {
166
166
  lines.push("");
167
- lines.push(` Redo (${data.redolog.count})`);
167
+ lines.push(` Issue Log (${data.issueLog.count})`);
168
168
  lines.push(` ${thin}`);
169
- for (const e of data.redolog.entries) {
169
+ for (const e of data.issueLog.entries) {
170
170
  lines.push(` [${e.step}] ${e.reason}${e.resolution ? ` -> ${e.resolution}` : ""}`);
171
171
  }
172
172
  }