aiwcli 0.12.7 → 0.12.8

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 (79) hide show
  1. package/dist/templates/CLAUDE.md +27 -0
  2. package/dist/templates/_shared/.claude/{commands/handoff.md → skills/handoff/SKILL.md} +3 -2
  3. package/dist/templates/_shared/.claude/{commands/handoff-resume.md → skills/handoff-resume/SKILL.md} +2 -1
  4. package/dist/templates/_shared/handoff-system/CLAUDE.md +433 -421
  5. package/dist/templates/_shared/lib-ts/CLAUDE.md +3 -3
  6. package/dist/templates/_shared/lib-ts/base/constants.ts +324 -306
  7. package/dist/templates/_shared/lib-ts/base/inference.ts +3 -3
  8. package/dist/templates/_shared/lib-ts/context/CLAUDE.md +134 -0
  9. package/dist/templates/_shared/scripts/status_line.ts +26 -29
  10. package/dist/templates/cc-native/.claude/commands/cc-native/specdev.md +1 -1
  11. package/dist/templates/cc-native/.claude/settings.json +3 -2
  12. package/dist/templates/cc-native/_cc-native/artifacts/CLAUDE.md +64 -0
  13. package/dist/templates/cc-native/_cc-native/{lib-ts/artifacts → artifacts/lib}/format.ts +597 -597
  14. package/dist/templates/cc-native/_cc-native/{lib-ts/artifacts → artifacts/lib}/index.ts +26 -26
  15. package/dist/templates/cc-native/_cc-native/{lib-ts/artifacts → artifacts/lib}/tracker.ts +107 -107
  16. package/dist/templates/cc-native/_cc-native/{lib-ts/artifacts → artifacts/lib}/write.ts +119 -119
  17. package/dist/templates/cc-native/_cc-native/hooks/CLAUDE.md +237 -247
  18. package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.ts +76 -76
  19. package/dist/templates/cc-native/_cc-native/hooks/validate_task_prompt.ts +76 -0
  20. package/dist/templates/cc-native/_cc-native/lib-ts/aggregate-agents.ts +163 -156
  21. package/dist/templates/cc-native/_cc-native/lib-ts/index.ts +116 -116
  22. package/dist/templates/cc-native/_cc-native/lib-ts/settings.ts +1 -1
  23. package/dist/templates/cc-native/_cc-native/lib-ts/types.ts +329 -329
  24. package/dist/templates/cc-native/_cc-native/plan-review/CLAUDE.md +149 -0
  25. package/dist/templates/cc-native/_cc-native/plan-review/agents/CLAUDE.md +143 -0
  26. package/dist/templates/cc-native/_cc-native/plan-review/agents/PLAN-ORCHESTRATOR.md +213 -0
  27. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-questions/PLAN-QUESTIONER.md +70 -0
  28. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/ARCH-EVOLUTION.md +62 -0
  29. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/ARCH-PATTERNS.md +61 -0
  30. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/ARCH-STRUCTURE.md +62 -0
  31. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/ASSUMPTION-TRACER.md +56 -0
  32. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/CLARITY-AUDITOR.md +53 -0
  33. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/COMPLETENESS-FEASIBILITY.md +66 -0
  34. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/COMPLETENESS-GAPS.md +70 -0
  35. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/COMPLETENESS-ORDERING.md +62 -0
  36. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/CONSTRAINT-VALIDATOR.md +72 -0
  37. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/DESIGN-ADR-VALIDATOR.md +61 -0
  38. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/DESIGN-SCALE-MATCHER.md +64 -0
  39. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/DEVILS-ADVOCATE.md +56 -0
  40. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/DOCUMENTATION-PHILOSOPHY.md +86 -0
  41. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/HANDOFF-READINESS.md +59 -0
  42. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/HIDDEN-COMPLEXITY.md +58 -0
  43. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/INCREMENTAL-DELIVERY.md +66 -0
  44. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/RISK-DEPENDENCY.md +62 -0
  45. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/RISK-FMEA.md +66 -0
  46. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/RISK-PREMORTEM.md +71 -0
  47. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/RISK-REVERSIBILITY.md +74 -0
  48. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/SCOPE-BOUNDARY.md +77 -0
  49. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/SIMPLICITY-GUARDIAN.md +62 -0
  50. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/SKEPTIC.md +68 -0
  51. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TESTDRIVEN-BEHAVIOR-AUDITOR.md +61 -0
  52. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TESTDRIVEN-CHARACTERIZATION.md +71 -0
  53. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TESTDRIVEN-FIRST-VALIDATOR.md +61 -0
  54. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TESTDRIVEN-PYRAMID-ANALYZER.md +61 -0
  55. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TRADEOFF-COSTS.md +67 -0
  56. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TRADEOFF-STAKEHOLDERS.md +65 -0
  57. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/VERIFY-COVERAGE.md +74 -0
  58. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/VERIFY-STRENGTH.md +69 -0
  59. package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/agent-selection.ts +163 -163
  60. package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/corroboration.ts +119 -119
  61. package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/graduation.ts +132 -132
  62. package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/orchestrator.ts +70 -70
  63. package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/output-builder.ts +130 -130
  64. package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/plan-questions.ts +102 -102
  65. package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/review-pipeline.ts +511 -511
  66. package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/reviewers/agent.ts +74 -74
  67. package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/reviewers/base/base-agent.ts +217 -217
  68. package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/reviewers/index.ts +12 -12
  69. package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/reviewers/providers/claude-agent.ts +66 -66
  70. package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/reviewers/providers/codex-agent.ts +185 -185
  71. package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/reviewers/providers/gemini-agent.ts +39 -39
  72. package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/reviewers/providers/orchestrator-claude-agent.ts +196 -196
  73. package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/reviewers/schemas.ts +201 -201
  74. package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/reviewers/types.ts +23 -23
  75. package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/verdict.ts +72 -72
  76. package/dist/templates/cc-native/_cc-native/{workflows → plan-review/workflows}/specdev.md +9 -9
  77. package/oclif.manifest.json +1 -1
  78. package/package.json +1 -1
  79. package/dist/templates/cc-native/_cc-native/lib-ts/artifacts.ts +0 -21
@@ -1,26 +1,26 @@
1
- /**
2
- * Barrel re-export for artifacts submodules.
3
- */
4
-
5
- export {
6
- formatReviewMarkdown,
7
- formatCombinedMarkdown,
8
- buildInlineReviewSummary,
9
- extractTopIssuesText,
10
- buildHighIssuesDocument,
11
- buildCorroborationReport,
12
- generateReviewIndex,
13
- buildCombinedJson,
14
- } from "./format.js";
15
-
16
- export {
17
- writeCombinedArtifacts,
18
- writeFile,
19
- writeFileNonCritical,
20
- } from "./write.js";
21
-
22
- export {
23
- writeReviewTracker,
24
- extractPreviousHashes,
25
- } from "./tracker.js";
26
- export type { ReviewTrackerEntry } from "./tracker.js";
1
+ /**
2
+ * Barrel re-export for artifacts submodules.
3
+ */
4
+
5
+ export {
6
+ formatReviewMarkdown,
7
+ formatCombinedMarkdown,
8
+ buildInlineReviewSummary,
9
+ extractTopIssuesText,
10
+ buildHighIssuesDocument,
11
+ buildCorroborationReport,
12
+ generateReviewIndex,
13
+ buildCombinedJson,
14
+ } from "./format.js";
15
+
16
+ export {
17
+ writeCombinedArtifacts,
18
+ writeFile,
19
+ writeFileNonCritical,
20
+ } from "./write.js";
21
+
22
+ export {
23
+ writeReviewTracker,
24
+ extractPreviousHashes,
25
+ } from "./tracker.js";
26
+ export type { ReviewTrackerEntry } from "./tracker.js";
@@ -1,107 +1,107 @@
1
- /**
2
- * Review tracker management — human-readable lifecycle summary.
3
- * Extracted from artifacts.ts.
4
- */
5
-
6
- import * as fs from "node:fs";
7
- import * as path from "node:path";
8
- import { logWarn } from "../../../_shared/lib-ts/base/logger.js";
9
-
10
- // ---------------------------------------------------------------------------
11
- // Types
12
- // ---------------------------------------------------------------------------
13
-
14
- export interface ReviewTrackerEntry {
15
- iteration: number;
16
- timestamp: string;
17
- planHash: string;
18
- verdict: string;
19
- decision: string;
20
- score: number;
21
- topIssues: string[];
22
- reviewFolder: string;
23
- }
24
-
25
- // ---------------------------------------------------------------------------
26
- // Tracker Writing
27
- // ---------------------------------------------------------------------------
28
-
29
- /**
30
- * Build or update the review-tracker.md in the cc-native reviews directory.
31
- */
32
- export function writeReviewTracker(
33
- ccNativeReviewsDir: string,
34
- entry: ReviewTrackerEntry,
35
- ): void {
36
- const trackerPath = path.join(ccNativeReviewsDir, "review-tracker.md");
37
-
38
- let existingContent = "";
39
- try {
40
- if (fs.existsSync(trackerPath)) {
41
- existingContent = fs.readFileSync(trackerPath, "utf-8");
42
- }
43
- } catch {
44
- // Fresh start
45
- }
46
-
47
- const previousHashes = extractPreviousHashes(existingContent);
48
- const hashChanged = previousHashes.length > 0 &&
49
- previousHashes[previousHashes.length - 1] !== entry.planHash;
50
-
51
- const lines: string[] = [];
52
- const verdictEmoji = entry.decision === "allow" ? "\u2705" : "\u274c";
53
- const changeNote = previousHashes.length > 0
54
- ? (hashChanged ? "\u2705 Plan was revised (hash changed)" : "\u26a0\ufe0f Plan unchanged since last review")
55
- : "Initial review";
56
-
57
- lines.push(`## Iteration ${entry.iteration} \u2014 ${entry.timestamp} \u2014 ${verdictEmoji} ${entry.verdict.toUpperCase()}`);
58
- lines.push("");
59
- lines.push(`- **Decision:** ${entry.decision}`);
60
- lines.push(`- **Score:** ${entry.score.toFixed(2)}`);
61
- lines.push(`- **Plan hash:** \`${entry.planHash}\``);
62
- lines.push(`- **Status:** ${changeNote}`);
63
- lines.push(`- **Full review:** [\`${path.basename(entry.reviewFolder)}/\`](${path.basename(entry.reviewFolder)}/index.md)`);
64
-
65
- if (entry.topIssues.length > 0) {
66
- lines.push("");
67
- lines.push("**Top issues:**");
68
- for (const issue of entry.topIssues) {
69
- lines.push(`- ${issue}`);
70
- }
71
- }
72
- lines.push("");
73
-
74
- let output: string;
75
- if (!existingContent || !existingContent.includes("# Plan Review Tracker")) {
76
- output = [
77
- "# Plan Review Tracker",
78
- "",
79
- "> Auto-generated by plan review hook. Shows review lifecycle across iterations.",
80
- "> Check `plan.md` in each iteration folder to diff plan changes.",
81
- "",
82
- ...lines,
83
- ].join("\n");
84
- } else {
85
- output = existingContent.trimEnd() + "\n\n" + lines.join("\n");
86
- }
87
-
88
- try {
89
- fs.writeFileSync(trackerPath, output, "utf-8");
90
- } catch (e) {
91
- logWarn("artifacts", `Failed to write review tracker: ${e}`);
92
- }
93
- }
94
-
95
- // ---------------------------------------------------------------------------
96
- // Helpers
97
- // ---------------------------------------------------------------------------
98
-
99
- export function extractPreviousHashes(content: string): string[] {
100
- const hashes: string[] = [];
101
- const regex = /\*\*Plan hash:\*\* `([a-f0-9]+)`/g;
102
- let match: RegExpExecArray | null;
103
- while ((match = regex.exec(content)) !== null) {
104
- hashes.push(match[1]!);
105
- }
106
- return hashes;
107
- }
1
+ /**
2
+ * Review tracker management — human-readable lifecycle summary.
3
+ * Extracted from artifacts.ts.
4
+ */
5
+
6
+ import * as fs from "node:fs";
7
+ import * as path from "node:path";
8
+ import { logWarn } from "../../../_shared/lib-ts/base/logger.js";
9
+
10
+ // ---------------------------------------------------------------------------
11
+ // Types
12
+ // ---------------------------------------------------------------------------
13
+
14
+ export interface ReviewTrackerEntry {
15
+ iteration: number;
16
+ timestamp: string;
17
+ planHash: string;
18
+ verdict: string;
19
+ decision: string;
20
+ score: number;
21
+ topIssues: string[];
22
+ reviewFolder: string;
23
+ }
24
+
25
+ // ---------------------------------------------------------------------------
26
+ // Tracker Writing
27
+ // ---------------------------------------------------------------------------
28
+
29
+ /**
30
+ * Build or update the review-tracker.md in the cc-native reviews directory.
31
+ */
32
+ export function writeReviewTracker(
33
+ ccNativeReviewsDir: string,
34
+ entry: ReviewTrackerEntry,
35
+ ): void {
36
+ const trackerPath = path.join(ccNativeReviewsDir, "review-tracker.md");
37
+
38
+ let existingContent = "";
39
+ try {
40
+ if (fs.existsSync(trackerPath)) {
41
+ existingContent = fs.readFileSync(trackerPath, "utf-8");
42
+ }
43
+ } catch {
44
+ // Fresh start
45
+ }
46
+
47
+ const previousHashes = extractPreviousHashes(existingContent);
48
+ const hashChanged = previousHashes.length > 0 &&
49
+ previousHashes[previousHashes.length - 1] !== entry.planHash;
50
+
51
+ const lines: string[] = [];
52
+ const verdictEmoji = entry.decision === "allow" ? "\u2705" : "\u274c";
53
+ const changeNote = previousHashes.length > 0
54
+ ? (hashChanged ? "\u2705 Plan was revised (hash changed)" : "\u26a0\ufe0f Plan unchanged since last review")
55
+ : "Initial review";
56
+
57
+ lines.push(`## Iteration ${entry.iteration} \u2014 ${entry.timestamp} \u2014 ${verdictEmoji} ${entry.verdict.toUpperCase()}`);
58
+ lines.push("");
59
+ lines.push(`- **Decision:** ${entry.decision}`);
60
+ lines.push(`- **Score:** ${entry.score.toFixed(2)}`);
61
+ lines.push(`- **Plan hash:** \`${entry.planHash}\``);
62
+ lines.push(`- **Status:** ${changeNote}`);
63
+ lines.push(`- **Full review:** [\`${path.basename(entry.reviewFolder)}/\`](${path.basename(entry.reviewFolder)}/index.md)`);
64
+
65
+ if (entry.topIssues.length > 0) {
66
+ lines.push("");
67
+ lines.push("**Top issues:**");
68
+ for (const issue of entry.topIssues) {
69
+ lines.push(`- ${issue}`);
70
+ }
71
+ }
72
+ lines.push("");
73
+
74
+ let output: string;
75
+ if (!existingContent || !existingContent.includes("# Plan Review Tracker")) {
76
+ output = [
77
+ "# Plan Review Tracker",
78
+ "",
79
+ "> Auto-generated by plan review hook. Shows review lifecycle across iterations.",
80
+ "> Check `plan.md` in each iteration folder to diff plan changes.",
81
+ "",
82
+ ...lines,
83
+ ].join("\n");
84
+ } else {
85
+ output = existingContent.trimEnd() + "\n\n" + lines.join("\n");
86
+ }
87
+
88
+ try {
89
+ fs.writeFileSync(trackerPath, output, "utf-8");
90
+ } catch (e) {
91
+ logWarn("artifacts", `Failed to write review tracker: ${e}`);
92
+ }
93
+ }
94
+
95
+ // ---------------------------------------------------------------------------
96
+ // Helpers
97
+ // ---------------------------------------------------------------------------
98
+
99
+ export function extractPreviousHashes(content: string): string[] {
100
+ const hashes: string[] = [];
101
+ const regex = /\*\*Plan hash:\*\* `([a-f0-9]+)`/g;
102
+ let match: RegExpExecArray | null;
103
+ while ((match = regex.exec(content)) !== null) {
104
+ hashes.push(match[1]!);
105
+ }
106
+ return hashes;
107
+ }
@@ -1,119 +1,119 @@
1
- /**
2
- * File I/O for review artifacts.
3
- * Extracted from artifacts.ts.
4
- */
5
-
6
- import * as fs from "node:fs";
7
- import * as path from "node:path";
8
- import { atomicWrite } from "../../../_shared/lib-ts/base/atomic-write.js";
9
- import { logDebug, logWarn, logError } from "../../../_shared/lib-ts/base/logger.js";
10
- import { sanitizeFilename } from "../../../_shared/lib-ts/base/constants.js";
11
- import { ENABLE_ROBUST_PLAN_WRITES } from "../constants.js";
12
- import type { CombinedReviewResult, CorroborationResult } from "../types.js";
13
- import {
14
- formatCombinedMarkdown,
15
- buildCombinedJson,
16
- generateReviewIndex,
17
- } from "./format.js";
18
-
19
- // ---------------------------------------------------------------------------
20
- // Artifact Writing
21
- // ---------------------------------------------------------------------------
22
-
23
- /**
24
- * Write combined review artifacts to context reviews folder.
25
- * Uses atomic writes for critical files when ENABLE_ROBUST_PLAN_WRITES is true.
26
- */
27
- export function writeCombinedArtifacts(
28
- base: string,
29
- plan: string,
30
- result: CombinedReviewResult,
31
- payload: Record<string, unknown>,
32
- settings?: Record<string, unknown>,
33
- contextReviewsDir?: string,
34
- reviewFolder?: string,
35
- iteration?: number,
36
- corroboration?: CorroborationResult,
37
- ): string {
38
- const outDir = reviewFolder ?? contextReviewsDir;
39
- if (!outDir) {
40
- throw new Error("Either contextReviewsDir or reviewFolder is required");
41
- }
42
-
43
- logDebug("utils", `Using review folder: ${outDir}`);
44
-
45
- try {
46
- fs.mkdirSync(outDir, { recursive: true });
47
- } catch (e: unknown) {
48
- logError("utils", `Cannot create directory ${outDir}: ${e}`);
49
- throw e;
50
- }
51
-
52
- // JSON write
53
- const jsonPath = path.join(outDir, "review.json");
54
- const jsonData = buildCombinedJson(result);
55
- writeFile(jsonPath, JSON.stringify(jsonData, null, 2));
56
-
57
- // Markdown write
58
- const mdPath = path.join(outDir, "review.md");
59
- const mdContent = formatCombinedMarkdown(result, settings, corroboration);
60
- writeFile(mdPath, mdContent);
61
-
62
- // Individual reviewer writes (non-critical)
63
- const reviewerOutputDir = path.join(outDir, "reviewer-output");
64
- try {
65
- fs.mkdirSync(reviewerOutputDir, { recursive: true });
66
- } catch (e) {
67
- logWarn("artifacts", `Failed to create reviewer-output dir: ${e}`);
68
- }
69
- for (const [name, r] of Object.entries(result.agents)) {
70
- if (r.data) {
71
- writeFileNonCritical(
72
- path.join(reviewerOutputDir, `${sanitizeFilename(name)}.json`),
73
- JSON.stringify(r.data, null, 2),
74
- );
75
- }
76
- }
77
-
78
- // Generate index.md for folder-based reviews
79
- if (reviewFolder) {
80
- const indexContent = generateReviewIndex(result, iteration, settings);
81
- writeFileNonCritical(path.join(outDir, "index.md"), indexContent);
82
- return path.join(outDir, "index.md");
83
- }
84
-
85
- return mdPath;
86
- }
87
-
88
- // ---------------------------------------------------------------------------
89
- // File Write Helpers
90
- // ---------------------------------------------------------------------------
91
-
92
- export function writeFile(filePath: string, content: string): void {
93
- try {
94
- if (ENABLE_ROBUST_PLAN_WRITES) {
95
- const [success, error] = atomicWrite(filePath, content);
96
- if (!success) throw new Error(`Atomic write failed: ${error}`);
97
- } else {
98
- fs.writeFileSync(filePath, content, "utf-8");
99
- }
100
- } catch (e: unknown) {
101
- logError("utils", `Failed to write ${path.basename(filePath)}: ${e}`);
102
- throw e;
103
- }
104
- }
105
-
106
- export function writeFileNonCritical(filePath: string, content: string): void {
107
- try {
108
- if (ENABLE_ROBUST_PLAN_WRITES) {
109
- const [success, error] = atomicWrite(filePath, content);
110
- if (!success) {
111
- logWarn("utils", `Failed to write ${path.basename(filePath)}: ${error}`);
112
- }
113
- } else {
114
- fs.writeFileSync(filePath, content, "utf-8");
115
- }
116
- } catch (e: unknown) {
117
- logWarn("utils", `Failed to write ${path.basename(filePath)}: ${e}`);
118
- }
119
- }
1
+ /**
2
+ * File I/O for review artifacts.
3
+ * Extracted from artifacts.ts.
4
+ */
5
+
6
+ import * as fs from "node:fs";
7
+ import * as path from "node:path";
8
+ import { atomicWrite } from "../../../_shared/lib-ts/base/atomic-write.js";
9
+ import { logDebug, logWarn, logError } from "../../../_shared/lib-ts/base/logger.js";
10
+ import { sanitizeFilename } from "../../../_shared/lib-ts/base/constants.js";
11
+ import { ENABLE_ROBUST_PLAN_WRITES } from "../../lib-ts/constants.js";
12
+ import type { CombinedReviewResult, CorroborationResult } from "../../lib-ts/types.js";
13
+ import {
14
+ formatCombinedMarkdown,
15
+ buildCombinedJson,
16
+ generateReviewIndex,
17
+ } from "./format.js";
18
+
19
+ // ---------------------------------------------------------------------------
20
+ // Artifact Writing
21
+ // ---------------------------------------------------------------------------
22
+
23
+ /**
24
+ * Write combined review artifacts to context reviews folder.
25
+ * Uses atomic writes for critical files when ENABLE_ROBUST_PLAN_WRITES is true.
26
+ */
27
+ export function writeCombinedArtifacts(
28
+ base: string,
29
+ plan: string,
30
+ result: CombinedReviewResult,
31
+ payload: Record<string, unknown>,
32
+ settings?: Record<string, unknown>,
33
+ contextReviewsDir?: string,
34
+ reviewFolder?: string,
35
+ iteration?: number,
36
+ corroboration?: CorroborationResult,
37
+ ): string {
38
+ const outDir = reviewFolder ?? contextReviewsDir;
39
+ if (!outDir) {
40
+ throw new Error("Either contextReviewsDir or reviewFolder is required");
41
+ }
42
+
43
+ logDebug("utils", `Using review folder: ${outDir}`);
44
+
45
+ try {
46
+ fs.mkdirSync(outDir, { recursive: true });
47
+ } catch (e: unknown) {
48
+ logError("utils", `Cannot create directory ${outDir}: ${e}`);
49
+ throw e;
50
+ }
51
+
52
+ // JSON write
53
+ const jsonPath = path.join(outDir, "review.json");
54
+ const jsonData = buildCombinedJson(result);
55
+ writeFile(jsonPath, JSON.stringify(jsonData, null, 2));
56
+
57
+ // Markdown write
58
+ const mdPath = path.join(outDir, "review.md");
59
+ const mdContent = formatCombinedMarkdown(result, settings, corroboration);
60
+ writeFile(mdPath, mdContent);
61
+
62
+ // Individual reviewer writes (non-critical)
63
+ const reviewerOutputDir = path.join(outDir, "reviewer-output");
64
+ try {
65
+ fs.mkdirSync(reviewerOutputDir, { recursive: true });
66
+ } catch (e) {
67
+ logWarn("artifacts", `Failed to create reviewer-output dir: ${e}`);
68
+ }
69
+ for (const [name, r] of Object.entries(result.agents)) {
70
+ if (r.data) {
71
+ writeFileNonCritical(
72
+ path.join(reviewerOutputDir, `${sanitizeFilename(name)}.json`),
73
+ JSON.stringify(r.data, null, 2),
74
+ );
75
+ }
76
+ }
77
+
78
+ // Generate index.md for folder-based reviews
79
+ if (reviewFolder) {
80
+ const indexContent = generateReviewIndex(result, iteration, settings);
81
+ writeFileNonCritical(path.join(outDir, "index.md"), indexContent);
82
+ return path.join(outDir, "index.md");
83
+ }
84
+
85
+ return mdPath;
86
+ }
87
+
88
+ // ---------------------------------------------------------------------------
89
+ // File Write Helpers
90
+ // ---------------------------------------------------------------------------
91
+
92
+ export function writeFile(filePath: string, content: string): void {
93
+ try {
94
+ if (ENABLE_ROBUST_PLAN_WRITES) {
95
+ const [success, error] = atomicWrite(filePath, content);
96
+ if (!success) throw new Error(`Atomic write failed: ${error}`);
97
+ } else {
98
+ fs.writeFileSync(filePath, content, "utf-8");
99
+ }
100
+ } catch (e: unknown) {
101
+ logError("utils", `Failed to write ${path.basename(filePath)}: ${e}`);
102
+ throw e;
103
+ }
104
+ }
105
+
106
+ export function writeFileNonCritical(filePath: string, content: string): void {
107
+ try {
108
+ if (ENABLE_ROBUST_PLAN_WRITES) {
109
+ const [success, error] = atomicWrite(filePath, content);
110
+ if (!success) {
111
+ logWarn("utils", `Failed to write ${path.basename(filePath)}: ${error}`);
112
+ }
113
+ } else {
114
+ fs.writeFileSync(filePath, content, "utf-8");
115
+ }
116
+ } catch (e: unknown) {
117
+ logWarn("utils", `Failed to write ${path.basename(filePath)}: ${e}`);
118
+ }
119
+ }