openplanr 1.2.8 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. package/README.md +7 -3
  2. package/dist/agents/task-parser.d.ts.map +1 -1
  3. package/dist/agents/task-parser.js +8 -34
  4. package/dist/agents/task-parser.js.map +1 -1
  5. package/dist/ai/prompts/system-prompts.d.ts +2 -2
  6. package/dist/ai/prompts/system-prompts.d.ts.map +1 -1
  7. package/dist/ai/prompts/system-prompts.js +7 -7
  8. package/dist/ai/schemas/ai-response-schemas.js +1 -1
  9. package/dist/ai/schemas/ai-response-schemas.js.map +1 -1
  10. package/dist/ai/types.d.ts.map +1 -1
  11. package/dist/ai/types.js +2 -0
  12. package/dist/ai/types.js.map +1 -1
  13. package/dist/cli/commands/backlog.d.ts +12 -0
  14. package/dist/cli/commands/backlog.d.ts.map +1 -1
  15. package/dist/cli/commands/backlog.js +88 -2
  16. package/dist/cli/commands/backlog.js.map +1 -1
  17. package/dist/cli/commands/config.d.ts.map +1 -1
  18. package/dist/cli/commands/config.js +8 -2
  19. package/dist/cli/commands/config.js.map +1 -1
  20. package/dist/cli/commands/linear.d.ts +8 -0
  21. package/dist/cli/commands/linear.d.ts.map +1 -0
  22. package/dist/cli/commands/linear.js +550 -0
  23. package/dist/cli/commands/linear.js.map +1 -0
  24. package/dist/cli/commands/quick.d.ts +17 -0
  25. package/dist/cli/commands/quick.d.ts.map +1 -1
  26. package/dist/cli/commands/quick.js +31 -15
  27. package/dist/cli/commands/quick.js.map +1 -1
  28. package/dist/cli/commands/revise.d.ts +9 -8
  29. package/dist/cli/commands/revise.d.ts.map +1 -1
  30. package/dist/cli/commands/revise.js +93 -25
  31. package/dist/cli/commands/revise.js.map +1 -1
  32. package/dist/cli/index.js +2 -0
  33. package/dist/cli/index.js.map +1 -1
  34. package/dist/models/schema.d.ts +43 -0
  35. package/dist/models/schema.d.ts.map +1 -1
  36. package/dist/models/schema.js +49 -0
  37. package/dist/models/schema.js.map +1 -1
  38. package/dist/models/types.d.ts +179 -3
  39. package/dist/models/types.d.ts.map +1 -1
  40. package/dist/services/artifact-gathering.d.ts +4 -0
  41. package/dist/services/artifact-gathering.d.ts.map +1 -1
  42. package/dist/services/artifact-gathering.js +1 -1
  43. package/dist/services/artifact-gathering.js.map +1 -1
  44. package/dist/services/artifact-service.d.ts +12 -1
  45. package/dist/services/artifact-service.d.ts.map +1 -1
  46. package/dist/services/artifact-service.js +49 -6
  47. package/dist/services/artifact-service.js.map +1 -1
  48. package/dist/services/atomic-write-service.d.ts +2 -2
  49. package/dist/services/atomic-write-service.js +2 -2
  50. package/dist/services/audit-log-service.d.ts +3 -6
  51. package/dist/services/audit-log-service.d.ts.map +1 -1
  52. package/dist/services/audit-log-service.js +4 -7
  53. package/dist/services/audit-log-service.js.map +1 -1
  54. package/dist/services/cascade-service.d.ts +2 -2
  55. package/dist/services/cascade-service.js +3 -3
  56. package/dist/services/cascade-service.js.map +1 -1
  57. package/dist/services/credentials-service.js +2 -2
  58. package/dist/services/credentials-service.js.map +1 -1
  59. package/dist/services/diff-service.d.ts +1 -1
  60. package/dist/services/diff-service.js +1 -1
  61. package/dist/services/evidence-verifier.d.ts +1 -1
  62. package/dist/services/evidence-verifier.d.ts.map +1 -1
  63. package/dist/services/evidence-verifier.js +5 -2
  64. package/dist/services/evidence-verifier.js.map +1 -1
  65. package/dist/services/git-service.d.ts +4 -4
  66. package/dist/services/git-service.js +4 -4
  67. package/dist/services/graph-integrity.d.ts +2 -3
  68. package/dist/services/graph-integrity.d.ts.map +1 -1
  69. package/dist/services/graph-integrity.js +2 -3
  70. package/dist/services/graph-integrity.js.map +1 -1
  71. package/dist/services/linear/body-formatters.d.ts +69 -0
  72. package/dist/services/linear/body-formatters.d.ts.map +1 -0
  73. package/dist/services/linear/body-formatters.js +183 -0
  74. package/dist/services/linear/body-formatters.js.map +1 -0
  75. package/dist/services/linear/constants.d.ts +61 -0
  76. package/dist/services/linear/constants.d.ts.map +1 -0
  77. package/dist/services/linear/constants.js +84 -0
  78. package/dist/services/linear/constants.js.map +1 -0
  79. package/dist/services/linear/errors.d.ts +14 -0
  80. package/dist/services/linear/errors.d.ts.map +1 -0
  81. package/dist/services/linear/errors.js +106 -0
  82. package/dist/services/linear/errors.js.map +1 -0
  83. package/dist/services/linear/estimate-resolver.d.ts +50 -0
  84. package/dist/services/linear/estimate-resolver.d.ts.map +1 -0
  85. package/dist/services/linear/estimate-resolver.js +82 -0
  86. package/dist/services/linear/estimate-resolver.js.map +1 -0
  87. package/dist/services/linear/plan-builders.d.ts +64 -0
  88. package/dist/services/linear/plan-builders.d.ts.map +1 -0
  89. package/dist/services/linear/plan-builders.js +237 -0
  90. package/dist/services/linear/plan-builders.js.map +1 -0
  91. package/dist/services/linear/scope-loaders.d.ts +79 -0
  92. package/dist/services/linear/scope-loaders.d.ts.map +1 -0
  93. package/dist/services/linear/scope-loaders.js +227 -0
  94. package/dist/services/linear/scope-loaders.js.map +1 -0
  95. package/dist/services/linear/strategy-context.d.ts +66 -0
  96. package/dist/services/linear/strategy-context.d.ts.map +1 -0
  97. package/dist/services/linear/strategy-context.js +121 -0
  98. package/dist/services/linear/strategy-context.js.map +1 -0
  99. package/dist/services/linear-mapping-service.d.ts +11 -0
  100. package/dist/services/linear-mapping-service.d.ts.map +1 -0
  101. package/dist/services/linear-mapping-service.js +220 -0
  102. package/dist/services/linear-mapping-service.js.map +1 -0
  103. package/dist/services/linear-pull-service.d.ts +137 -0
  104. package/dist/services/linear-pull-service.d.ts.map +1 -0
  105. package/dist/services/linear-pull-service.js +720 -0
  106. package/dist/services/linear-pull-service.js.map +1 -0
  107. package/dist/services/linear-push-service.d.ts +86 -0
  108. package/dist/services/linear-push-service.d.ts.map +1 -0
  109. package/dist/services/linear-push-service.js +956 -0
  110. package/dist/services/linear-push-service.js.map +1 -0
  111. package/dist/services/linear-service.d.ts +122 -0
  112. package/dist/services/linear-service.d.ts.map +1 -0
  113. package/dist/services/linear-service.js +361 -0
  114. package/dist/services/linear-service.js.map +1 -0
  115. package/dist/services/prompt-service.d.ts +19 -0
  116. package/dist/services/prompt-service.d.ts.map +1 -1
  117. package/dist/services/prompt-service.js +64 -0
  118. package/dist/services/prompt-service.js.map +1 -1
  119. package/dist/services/revise-apply-service.d.ts +55 -0
  120. package/dist/services/revise-apply-service.d.ts.map +1 -0
  121. package/dist/services/revise-apply-service.js +255 -0
  122. package/dist/services/revise-apply-service.js.map +1 -0
  123. package/dist/services/revise-cache-service.d.ts +1 -1
  124. package/dist/services/revise-cache-service.js +1 -1
  125. package/dist/services/revise-plan-service.d.ts +38 -0
  126. package/dist/services/revise-plan-service.d.ts.map +1 -0
  127. package/dist/services/revise-plan-service.js +151 -0
  128. package/dist/services/revise-plan-service.js.map +1 -0
  129. package/dist/services/revise-service.d.ts +18 -11
  130. package/dist/services/revise-service.d.ts.map +1 -1
  131. package/dist/services/revise-service.js +57 -12
  132. package/dist/services/revise-service.js.map +1 -1
  133. package/dist/services/template-sections.d.ts +1 -1
  134. package/dist/services/template-sections.js +1 -1
  135. package/dist/templates/backlog/backlog-item.md.hbs +3 -0
  136. package/dist/templates/quick/quick-task.md.hbs +6 -0
  137. package/dist/utils/diff.d.ts +22 -1
  138. package/dist/utils/diff.d.ts.map +1 -1
  139. package/dist/utils/diff.js +136 -1
  140. package/dist/utils/diff.js.map +1 -1
  141. package/dist/utils/markdown.d.ts +23 -0
  142. package/dist/utils/markdown.d.ts.map +1 -1
  143. package/dist/utils/markdown.js +79 -0
  144. package/dist/utils/markdown.js.map +1 -1
  145. package/package.json +3 -2
@@ -1,6 +1,7 @@
1
1
  import { checkbox, confirm, editor, input, password, select } from '@inquirer/prompts';
2
2
  import { logger } from '../utils/logger.js';
3
3
  import { isNonInteractive } from './interactive-state.js';
4
+ import { getTeamProjects } from './linear-service.js';
4
5
  /** Prompt the user for a single line of text input. Falls back to defaultValue in non-interactive mode. */
5
6
  export async function promptText(message, defaultValue) {
6
7
  if (isNonInteractive()) {
@@ -93,6 +94,69 @@ export async function promptReviseConfirm(artifactId) {
93
94
  default: 'apply',
94
95
  });
95
96
  }
97
+ // ---------------------------------------------------------------------------
98
+ // Linear integration prompts
99
+ // ---------------------------------------------------------------------------
100
+ /**
101
+ * First-time epic-push: offer the three mapping strategies and (for
102
+ * `milestone-of` / `label-on`) let the user pick an existing Linear project
103
+ * to attach into. Pure UI + one read-only SDK call (`getTeamProjects`).
104
+ */
105
+ export async function promptMappingStrategy(client, teamId, epicId) {
106
+ if (isNonInteractive())
107
+ return null;
108
+ const strategy = await select({
109
+ message: `How should ${epicId} map to Linear?`,
110
+ choices: [
111
+ {
112
+ name: '[a] Create a new Linear project (recommended — Epic = Project, v1 behavior)',
113
+ value: 'project',
114
+ },
115
+ { name: '[b] Attach as a milestone of an existing Linear project', value: 'milestone-of' },
116
+ { name: '[c] Attach as a label on an existing Linear project', value: 'label-on' },
117
+ ],
118
+ default: 'project',
119
+ });
120
+ if (strategy === 'project') {
121
+ return { strategy };
122
+ }
123
+ const projects = await getTeamProjects(client, teamId);
124
+ if (projects.length === 0) {
125
+ logger.warn('This team has no Linear projects yet — falling back to creating a new one (strategy: project).');
126
+ return { strategy: 'project' };
127
+ }
128
+ const targetProjectId = await select({
129
+ message: `Pick the target Linear project for ${epicId}:`,
130
+ choices: projects.map((p) => ({ name: `${p.name} (${p.url})`, value: p.id })),
131
+ });
132
+ return { strategy, targetProjectId };
133
+ }
134
+ /**
135
+ * First-time QT / BL push: let the user pick the Linear project that will
136
+ * host `QT-*` and `BL-*` issues (stored in `linear.standaloneProjectId`).
137
+ */
138
+ export async function promptStandaloneProject(client, teamId) {
139
+ if (isNonInteractive())
140
+ return null;
141
+ const projects = await getTeamProjects(client, teamId);
142
+ if (projects.length === 0) {
143
+ logger.warn('This team has no Linear projects yet — create one in Linear first, then re-run the push.');
144
+ return null;
145
+ }
146
+ const choice = await select({
147
+ message: 'Pick the Linear project that will host Planr quick tasks & backlog items:',
148
+ choices: [
149
+ ...projects.map((p) => ({ name: `${p.name} (${p.url})`, value: p.id })),
150
+ { name: '[cancel]', value: '__cancel__' },
151
+ ],
152
+ });
153
+ if (choice === '__cancel__')
154
+ return null;
155
+ const picked = projects.find((p) => p.id === choice);
156
+ if (!picked)
157
+ return null;
158
+ return { projectId: picked.id, projectName: picked.name };
159
+ }
96
160
  /**
97
161
  * Typed-YES confirmation gate for `--yes` bulk-apply runs.
98
162
  *
@@ -1 +1 @@
1
- {"version":3,"file":"prompt-service.js","sourceRoot":"","sources":["../../src/services/prompt-service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"prompt-service.js","sourceRoot":"","sources":["../../src/services/prompt-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Replay a previously-written revise audit to disk without any model calls.
3
+ *
4
+ * Implements after `planr revise --dry-run` produces an audit log
5
+ * with the proposed diffs, `planr revise --apply-from <audit>` reads those
6
+ * diffs and writes them to the corresponding artifacts. Zero tokens spent
7
+ * in this mode.
8
+ *
9
+ * Pipeline:
10
+ * 1. Clean-tree gate (same as normal revise)
11
+ * 2. Parse the audit (via `revise-plan-service`) → list of replayable entries
12
+ * 3. Filter to `would-apply` entries that have a diff + artifact path
13
+ * 4. Per entry:
14
+ * a. Read current artifact content
15
+ * b. Apply the stored diff; if the diff doesn't land cleanly (the
16
+ * source has drifted since the dry-run), skip the entry and
17
+ * record the skip reason in the new audit
18
+ * c. Atomic write with sidecar backup
19
+ * d. Append an `applied-from-plan` entry to the new audit log
20
+ * 5. Post-flight graph-integrity check + git rollback on break
21
+ *
22
+ * Safety gates preserved vs. normal apply:
23
+ * - Clean-tree gate ✓
24
+ * - Atomic writes (temp file + rename) ✓
25
+ * - Post-flight graph integrity + git rollback ✓
26
+ * - Per-artifact confirmation (prompt unless `--yes`) ✓
27
+ *
28
+ * Note: sidecar `.bak` files are deliberately NOT written on this path.
29
+ * Rollback already flows through git (clean-tree gate guarantees HEAD is a
30
+ * valid restore point), so per-file backups would be redundant noise in
31
+ * `.planr/reports/`. The atomic-write guarantee covers partial-write
32
+ * crashes; git covers "I wish I hadn't applied that."
33
+ *
34
+ * Deliberately NOT run on replay:
35
+ * - AI model calls (the point of this feature)
36
+ * - Evidence verification (the dry-run already verified; nothing changes
37
+ * between dry-run and apply that evidence verification would catch that
38
+ * the diff-apply staleness check doesn't already catch)
39
+ * - `--cascade` / `--all` orchestration (the audit already encodes the
40
+ * cascade order as entry order)
41
+ */
42
+ import type { OpenPlanrConfig } from '../models/types.js';
43
+ export interface ApplyFromAuditOptions {
44
+ projectDir: string;
45
+ config: OpenPlanrConfig;
46
+ auditPath: string;
47
+ allowDirty: boolean;
48
+ /** Print the plan without writing — useful to confirm what would replay. */
49
+ dryRun: boolean;
50
+ /** Skip per-artifact confirmation; still requires typed-YES in an interactive TTY. */
51
+ yes: boolean;
52
+ }
53
+ /** Returns the process exit code. 0 on success, 1 on fatal error, non-zero on partial/rollback. */
54
+ export declare function runApplyFromAudit(opts: ApplyFromAuditOptions): Promise<number>;
55
+ //# sourceMappingURL=revise-apply-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"revise-apply-service.d.ts","sourceRoot":"","sources":["../../src/services/revise-apply-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAIH,OAAO,KAAK,EAAE,eAAe,EAAoB,MAAM,oBAAoB,CAAC;AAW5E,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,eAAe,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;IACpB,4EAA4E;IAC5E,MAAM,EAAE,OAAO,CAAC;IAChB,sFAAsF;IACtF,GAAG,EAAE,OAAO,CAAC;CACd;AAED,mGAAmG;AACnG,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC,CAyMpF"}
@@ -0,0 +1,255 @@
1
+ /**
2
+ * Replay a previously-written revise audit to disk without any model calls.
3
+ *
4
+ * Implements after `planr revise --dry-run` produces an audit log
5
+ * with the proposed diffs, `planr revise --apply-from <audit>` reads those
6
+ * diffs and writes them to the corresponding artifacts. Zero tokens spent
7
+ * in this mode.
8
+ *
9
+ * Pipeline:
10
+ * 1. Clean-tree gate (same as normal revise)
11
+ * 2. Parse the audit (via `revise-plan-service`) → list of replayable entries
12
+ * 3. Filter to `would-apply` entries that have a diff + artifact path
13
+ * 4. Per entry:
14
+ * a. Read current artifact content
15
+ * b. Apply the stored diff; if the diff doesn't land cleanly (the
16
+ * source has drifted since the dry-run), skip the entry and
17
+ * record the skip reason in the new audit
18
+ * c. Atomic write with sidecar backup
19
+ * d. Append an `applied-from-plan` entry to the new audit log
20
+ * 5. Post-flight graph-integrity check + git rollback on break
21
+ *
22
+ * Safety gates preserved vs. normal apply:
23
+ * - Clean-tree gate ✓
24
+ * - Atomic writes (temp file + rename) ✓
25
+ * - Post-flight graph integrity + git rollback ✓
26
+ * - Per-artifact confirmation (prompt unless `--yes`) ✓
27
+ *
28
+ * Note: sidecar `.bak` files are deliberately NOT written on this path.
29
+ * Rollback already flows through git (clean-tree gate guarantees HEAD is a
30
+ * valid restore point), so per-file backups would be redundant noise in
31
+ * `.planr/reports/`. The atomic-write guarantee covers partial-write
32
+ * crashes; git covers "I wish I hadn't applied that."
33
+ *
34
+ * Deliberately NOT run on replay:
35
+ * - AI model calls (the point of this feature)
36
+ * - Evidence verification (the dry-run already verified; nothing changes
37
+ * between dry-run and apply that evidence verification would catch that
38
+ * the diff-apply staleness check doesn't already catch)
39
+ * - `--cascade` / `--all` orchestration (the audit already encodes the
40
+ * cascade order as entry order)
41
+ */
42
+ import path from 'node:path';
43
+ import chalk from 'chalk';
44
+ import { applyUnifiedDiff } from '../utils/diff.js';
45
+ import { readFile } from '../utils/fs.js';
46
+ import { display, logger } from '../utils/logger.js';
47
+ import { atomicWriteFile } from './atomic-write-service.js';
48
+ import { createAuditLogWriter } from './audit-log-service.js';
49
+ import { checkCleanTree, checkoutPaths } from './git-service.js';
50
+ import { checkGraphIntegrity } from './graph-integrity.js';
51
+ import { confirmBulkRevise, promptReviseConfirm } from './prompt-service.js';
52
+ import { filterReplayable, readPlanFromAudit } from './revise-plan-service.js';
53
+ /** Returns the process exit code. 0 on success, 1 on fatal error, non-zero on partial/rollback. */
54
+ export async function runApplyFromAudit(opts) {
55
+ const { projectDir, config, auditPath, allowDirty, dryRun, yes } = opts;
56
+ logger.heading(`Apply revise plan from ${path.basename(auditPath)}${dryRun ? ' (dry-run)' : ''}`);
57
+ logger.dim('Mode: replay — zero AI tokens will be spent.');
58
+ // --- Layer 1: clean-tree gate -------------------------------------------
59
+ const treeCheck = await checkCleanTree(projectDir, { allowDirty });
60
+ if (!treeCheck.ok) {
61
+ logger.error(treeCheck.message);
62
+ return 1;
63
+ }
64
+ if (treeCheck.status.kind !== 'clean') {
65
+ logger.warn(treeCheck.message);
66
+ }
67
+ // --- Layer 2: parse the audit -------------------------------------------
68
+ let plan;
69
+ try {
70
+ plan = readPlanFromAudit(auditPath);
71
+ }
72
+ catch (err) {
73
+ logger.error(err instanceof Error ? err.message : String(err));
74
+ return 1;
75
+ }
76
+ const replayable = filterReplayable(plan);
77
+ logger.info(`Parsed ${plan.entries.length} audit entries (${replayable.length} replayable, ${plan.entries.length - replayable.length} skipped/flagged without diff).`);
78
+ if (replayable.length === 0) {
79
+ logger.warn('No replayable entries (would-apply + diff + artifact path). Nothing to do.');
80
+ return 0;
81
+ }
82
+ // --- Bulk confirmation: typed-YES for TTY, flag-only for CI -------------
83
+ if (yes && !dryRun) {
84
+ const summary = buildReplaySummary(auditPath, replayable);
85
+ const confirmed = await confirmBulkRevise(summary);
86
+ if (!confirmed) {
87
+ logger.dim('Confirmation declined — exiting without changes.');
88
+ return 0;
89
+ }
90
+ }
91
+ // --- New audit log for the apply-from-plan run --------------------------
92
+ const writer = createAuditLogWriter({
93
+ projectDir,
94
+ scope: `${plan.scope}-applied`,
95
+ cascade: false,
96
+ dryRun,
97
+ format: 'md',
98
+ });
99
+ logger.dim(`Apply audit log: ${writer.path}`);
100
+ // --- Per-entry replay ---------------------------------------------------
101
+ const affectedPaths = [];
102
+ let applied = 0;
103
+ let stale = 0;
104
+ let conflicts = 0;
105
+ let skipped = 0;
106
+ let userQuit = false;
107
+ for (let i = 0; i < replayable.length; i++) {
108
+ if (userQuit)
109
+ break;
110
+ const entry = replayable[i];
111
+ const progress = `[${i + 1}/${replayable.length}] ${entry.artifactId}`;
112
+ if (!entry.artifactPath) {
113
+ skipped++;
114
+ recordSkip(writer, entry, 'stale-skipped', 'no artifact path recorded in plan');
115
+ continue;
116
+ }
117
+ let currentContent;
118
+ try {
119
+ currentContent = await readFile(entry.artifactPath);
120
+ }
121
+ catch (err) {
122
+ stale++;
123
+ recordSkip(writer, entry, 'stale-skipped', `cannot read artifact: ${err instanceof Error ? err.message : String(err)}`);
124
+ logger.warn(`${progress}: stale — artifact not readable.`);
125
+ continue;
126
+ }
127
+ const patch = applyUnifiedDiff(currentContent, entry.diff ?? '');
128
+ if (!patch.ok) {
129
+ conflicts++;
130
+ recordSkip(writer, entry, 'conflict-skipped', patch.error ?? 'diff did not apply cleanly');
131
+ logger.warn(`${progress}: conflict — ${patch.error}`);
132
+ continue;
133
+ }
134
+ // Per-artifact confirmation (skipped when --yes or --dry-run).
135
+ if (!dryRun && !yes) {
136
+ display.separator(60);
137
+ display.heading(` ${progress}: ${chalk.yellow('REPLAY REVISE')}`);
138
+ display.line(` Artifact: ${entry.artifactId}`);
139
+ display.line(` Rationale: ${entry.rationale}`);
140
+ display.line('');
141
+ display.line(' Diff:');
142
+ const diffPreview = (entry.diff ?? '')
143
+ .split('\n')
144
+ .map((l) => ` ${colorizeDiffLine(l)}`)
145
+ .join('\n');
146
+ display.line(diffPreview);
147
+ display.separator(60);
148
+ const action = await promptReviseConfirm(entry.artifactId);
149
+ if (action === 'skip') {
150
+ skipped++;
151
+ recordSkip(writer, entry, 'skipped-by-user', 'user declined at replay prompt');
152
+ logger.dim(`${progress}: skipped by user.`);
153
+ continue;
154
+ }
155
+ if (action === 'quit') {
156
+ recordSkip(writer, entry, 'skipped-by-user', 'user quit replay at this entry');
157
+ userQuit = true;
158
+ break;
159
+ }
160
+ // For 'diff-again' we just continue; the diff was already shown. For
161
+ // 'edit-rationale' we accept as-is (replay doesn't let you edit).
162
+ }
163
+ if (dryRun) {
164
+ writer.appendEntry({
165
+ ...entry,
166
+ outcome: 'would-apply',
167
+ timestamp: new Date().toISOString(),
168
+ });
169
+ applied++;
170
+ logger.info(`${progress}: would apply (dry-run).`);
171
+ continue;
172
+ }
173
+ // Atomic write (temp file + rename). No sidecar backup — git covers
174
+ // rollback via the clean-tree gate + post-flight checkout.
175
+ try {
176
+ await atomicWriteFile(entry.artifactPath, patch.result ?? '');
177
+ affectedPaths.push(path.relative(projectDir, entry.artifactPath) || entry.artifactPath);
178
+ applied++;
179
+ writer.appendEntry({
180
+ ...entry,
181
+ outcome: 'applied-from-plan',
182
+ timestamp: new Date().toISOString(),
183
+ });
184
+ logger.info(`${progress}: ${chalk.green('applied')}.`);
185
+ }
186
+ catch (err) {
187
+ conflicts++;
188
+ recordSkip(writer, entry, 'conflict-skipped', `write failed: ${err instanceof Error ? err.message : String(err)}`);
189
+ logger.error(`${progress}: write failed — ${err}`);
190
+ }
191
+ }
192
+ // --- Post-flight graph integrity + rollback -----------------------------
193
+ let exitCode = 0;
194
+ if (!dryRun && affectedPaths.length > 0) {
195
+ const integrity = await checkGraphIntegrity(projectDir, config);
196
+ if (!integrity.ok) {
197
+ logger.error(`Post-flight graph integrity broken: ${integrity.issues.length} issue(s). Rolling back…`);
198
+ if (treeCheck.status.kind === 'clean') {
199
+ await checkoutPaths(projectDir, affectedPaths);
200
+ logger.info(`Rolled back ${affectedPaths.length} artifact path(s) to HEAD.`);
201
+ }
202
+ else {
203
+ logger.warn('Cannot rollback — pre-run tree was dirty. Inspect changes manually.');
204
+ }
205
+ exitCode = 1;
206
+ }
207
+ else {
208
+ logger.dim('Post-flight graph integrity: ok.');
209
+ }
210
+ }
211
+ writer.close();
212
+ // --- Summary ------------------------------------------------------------
213
+ display.separator(60);
214
+ display.heading(' Replay summary');
215
+ display.line(` Applied: ${chalk.green(String(applied))}`);
216
+ display.line(` Stale-skipped: ${stale} (artifact missing or unreadable)`);
217
+ display.line(` Conflict-skipped: ${conflicts} (diff did not apply cleanly)`);
218
+ display.line(` User-skipped: ${skipped}`);
219
+ display.line(` ${chalk.bold('AI tokens spent: 0')} (replay mode — zero model calls)`);
220
+ if (!dryRun && applied > 0 && exitCode === 0) {
221
+ display.line('');
222
+ display.line(` Suggested commit: ${chalk.cyan(`git commit -am "chore(plan): apply revise plan ${plan.scope}"`)}`);
223
+ }
224
+ display.separator(60);
225
+ return exitCode;
226
+ }
227
+ function recordSkip(writer, entry, outcome, reason) {
228
+ writer.appendEntry({
229
+ ...entry,
230
+ outcome,
231
+ error: reason,
232
+ timestamp: new Date().toISOString(),
233
+ });
234
+ }
235
+ function buildReplaySummary(auditPath, entries) {
236
+ const head = `About to replay ${entries.length} revise entries from ${path.basename(auditPath)}.`;
237
+ const sample = entries
238
+ .slice(0, 8)
239
+ .map((e) => ` - ${e.artifactId} (${e.outcome} → applied-from-plan)`)
240
+ .join('\n');
241
+ const tail = entries.length > 8 ? `\n … and ${entries.length - 8} more` : '';
242
+ return `${head}\nZero model calls will be made.\n${sample}${tail}`;
243
+ }
244
+ function colorizeDiffLine(line) {
245
+ if (line.startsWith('+++') || line.startsWith('---'))
246
+ return chalk.bold(line);
247
+ if (line.startsWith('@@'))
248
+ return chalk.cyan(line);
249
+ if (line.startsWith('+'))
250
+ return chalk.green(line);
251
+ if (line.startsWith('-'))
252
+ return chalk.red(line);
253
+ return chalk.dim(line);
254
+ }
255
+ //# sourceMappingURL=revise-apply-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"revise-apply-service.js","sourceRoot":"","sources":["../../src/services/revise-apply-service.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Content-hash run cache for `planr revise` (EPIC-003, FEAT-014 §2.0).
2
+ * Content-hash run cache for `planr revise`.
3
3
  *
4
4
  * Between runs, we hash each artifact's raw content (+ the codebase-digest
5
5
  * input, when present) and skip artifacts whose hash matches the last
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Content-hash run cache for `planr revise` (EPIC-003, FEAT-014 §2.0).
2
+ * Content-hash run cache for `planr revise`.
3
3
  *
4
4
  * Between runs, we hash each artifact's raw content (+ the codebase-digest
5
5
  * input, when present) and skip artifacts whose hash matches the last
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Revise plan parser.
3
+ *
4
+ * A "plan" is a previously-written revise audit log that we replay to disk
5
+ * without any model calls. This service parses a Markdown audit file
6
+ * emitted by `audit-log-service.ts` back into structured `ReviseAuditEntry`
7
+ * records that the CLI's apply-from-audit path can replay.
8
+ *
9
+ * Parsing is deliberately strict about structure but tolerant of
10
+ * whitespace — audit files are written by us and edited by no-one, so we
11
+ * can rely on the heading hierarchy and section markers. If a user has
12
+ * hand-edited the audit, the parser surfaces specific errors so the user
13
+ * can fix or discard the file rather than silently getting bad replays.
14
+ *
15
+ * Future extension: we may emit a sidecar `.plan.json` next to the
16
+ * Markdown audit to carry content hashes and `revisedMarkdown` without
17
+ * parsing overhead. The Markdown path remains supported indefinitely —
18
+ * older audits predate any sidecar format and still need replay support.
19
+ */
20
+ import type { ReviseAuditEntry } from '../models/types.js';
21
+ export interface ReplayablePlan {
22
+ /** Absolute path of the audit file this plan was parsed from. */
23
+ sourcePath: string;
24
+ /** Scope recorded in the audit header (e.g., "EPIC-001"). */
25
+ scope: string;
26
+ /** When the dry-run was started, from the audit header. */
27
+ startedAt?: string;
28
+ /** All entries, preserving original order. Includes skipped/flagged for the summary. */
29
+ entries: ReviseAuditEntry[];
30
+ }
31
+ /**
32
+ * Parse a revise Markdown audit log into its constituent entries.
33
+ * Throws if the file cannot be read, is empty, or has no entries.
34
+ */
35
+ export declare function readPlanFromAudit(auditPath: string): ReplayablePlan;
36
+ /** Entries that can actually be written on replay (have a diff and target path). */
37
+ export declare function filterReplayable(plan: ReplayablePlan): ReviseAuditEntry[];
38
+ //# sourceMappingURL=revise-plan-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"revise-plan-service.d.ts","sourceRoot":"","sources":["../../src/services/revise-plan-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,KAAK,EACV,gBAAgB,EAIjB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,cAAc;IAC7B,iEAAiE;IACjE,UAAU,EAAE,MAAM,CAAC;IACnB,6DAA6D;IAC7D,KAAK,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wFAAwF;IACxF,OAAO,EAAE,gBAAgB,EAAE,CAAC;CAC7B;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,CAuBnE;AAED,oFAAoF;AACpF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,cAAc,GAAG,gBAAgB,EAAE,CAIzE"}
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Revise plan parser.
3
+ *
4
+ * A "plan" is a previously-written revise audit log that we replay to disk
5
+ * without any model calls. This service parses a Markdown audit file
6
+ * emitted by `audit-log-service.ts` back into structured `ReviseAuditEntry`
7
+ * records that the CLI's apply-from-audit path can replay.
8
+ *
9
+ * Parsing is deliberately strict about structure but tolerant of
10
+ * whitespace — audit files are written by us and edited by no-one, so we
11
+ * can rely on the heading hierarchy and section markers. If a user has
12
+ * hand-edited the audit, the parser surfaces specific errors so the user
13
+ * can fix or discard the file rather than silently getting bad replays.
14
+ *
15
+ * Future extension: we may emit a sidecar `.plan.json` next to the
16
+ * Markdown audit to carry content hashes and `revisedMarkdown` without
17
+ * parsing overhead. The Markdown path remains supported indefinitely —
18
+ * older audits predate any sidecar format and still need replay support.
19
+ */
20
+ import { readFileSync } from 'node:fs';
21
+ /**
22
+ * Parse a revise Markdown audit log into its constituent entries.
23
+ * Throws if the file cannot be read, is empty, or has no entries.
24
+ */
25
+ export function readPlanFromAudit(auditPath) {
26
+ let raw;
27
+ try {
28
+ raw = readFileSync(auditPath, 'utf-8');
29
+ }
30
+ catch (err) {
31
+ throw new Error(`Cannot read audit file at ${auditPath}: ${err instanceof Error ? err.message : String(err)}`);
32
+ }
33
+ if (raw.length === 0) {
34
+ throw new Error(`Audit file ${auditPath} is empty.`);
35
+ }
36
+ const { scope, startedAt } = parseHeader(raw, auditPath);
37
+ const entries = parseEntries(raw, auditPath);
38
+ if (entries.length === 0) {
39
+ throw new Error(`Audit file ${auditPath} contains no entries — nothing to apply. Re-run revise with --dry-run first.`);
40
+ }
41
+ return { sourcePath: auditPath, scope, startedAt, entries };
42
+ }
43
+ /** Entries that can actually be written on replay (have a diff and target path). */
44
+ export function filterReplayable(plan) {
45
+ return plan.entries.filter((e) => e.outcome === 'would-apply' && e.artifactPath && e.diff && e.diff.length > 0);
46
+ }
47
+ // ---------------------------------------------------------------------------
48
+ // Parsing internals
49
+ // ---------------------------------------------------------------------------
50
+ function parseHeader(raw, auditPath) {
51
+ const title = raw.match(/^#\s+Revise audit\s+—\s+([A-Z]+-\d{3,})\b/m);
52
+ if (!title) {
53
+ throw new Error(`Audit file ${auditPath} does not start with a recognizable header (expected "# Revise audit — <SCOPE>").`);
54
+ }
55
+ const scope = title[1];
56
+ const started = raw.match(/started=([0-9T:\-.Z]+)/);
57
+ return { scope, startedAt: started ? started[1] : undefined };
58
+ }
59
+ /**
60
+ * Split the audit body into entries by the `### [outcome] ArtifactId` heading.
61
+ * Each entry then parses independently; any entry that fails to parse is
62
+ * collected with a reason in its error field rather than aborting the whole
63
+ * parse — the caller filters to `would-apply` for replay, so skipped/malformed
64
+ * entries simply won't be replayed.
65
+ */
66
+ function parseEntries(raw, auditPath) {
67
+ // The `## Entries` / `## Summary` headings bookend the body; we scan between them.
68
+ const entriesStart = raw.indexOf('\n## Entries');
69
+ const summaryStart = raw.indexOf('\n## Summary');
70
+ const body = entriesStart >= 0
71
+ ? raw.slice(entriesStart, summaryStart >= 0 ? summaryStart : raw.length)
72
+ : raw;
73
+ // Split on the entry heading. Each chunk (except the first, which is the
74
+ // `## Entries` preamble) corresponds to one entry.
75
+ const chunks = body.split(/\n(?=### \[)/);
76
+ const entries = [];
77
+ for (const chunk of chunks) {
78
+ const trimmed = chunk.trim();
79
+ if (!trimmed.startsWith('### ['))
80
+ continue;
81
+ const parsed = parseEntry(trimmed, auditPath);
82
+ if (parsed)
83
+ entries.push(parsed);
84
+ }
85
+ return entries;
86
+ }
87
+ function parseEntry(chunk, _auditPath) {
88
+ const heading = chunk.match(/^### \[([^\]]+)\]\s+(\S+)/);
89
+ if (!heading)
90
+ return null;
91
+ const outcome = heading[1];
92
+ const artifactId = heading[2];
93
+ const artifactPathMatch = chunk.match(/\n>\s+(\/[^\s\n]+\.md)/);
94
+ const artifactPath = artifactPathMatch ? artifactPathMatch[1] : undefined;
95
+ const timestampMatch = chunk.match(/timestamp=([0-9T:\-.Z]+)/);
96
+ const timestamp = timestampMatch ? timestampMatch[1] : new Date().toISOString();
97
+ const rationaleMatch = chunk.match(/\*\*Rationale:\*\*\s+([\s\S]*?)(?=\n\n\*\*|\n\n```|$)/);
98
+ const rationale = rationaleMatch ? rationaleMatch[1].trim() : '';
99
+ const evidence = parseEvidenceList(chunk);
100
+ const ambiguous = parseAmbiguousList(chunk);
101
+ const diff = parseDiffBlock(chunk);
102
+ return {
103
+ artifactId,
104
+ artifactPath,
105
+ outcome,
106
+ rationale,
107
+ evidence,
108
+ ambiguous,
109
+ diff,
110
+ timestamp,
111
+ // Older audits don't carry these; the replay flow is responsible for
112
+ // computing / verifying them against live content when present.
113
+ };
114
+ }
115
+ function parseEvidenceList(chunk) {
116
+ // Match from `**Evidence:**` heading to the next `**Xxx:**` / `## ` /
117
+ // fenced-diff / end.
118
+ const section = chunk.match(/\*\*Evidence:\*\*\s*\n([\s\S]*?)(?=\n\n\*\*[A-Z]|\n\n```|\n## |$)/);
119
+ if (!section)
120
+ return [];
121
+ const out = [];
122
+ const lineRe = /^-\s+\[([a-z_]+)\]\s+`([^`]+)`(?:\s+—\s+"([\s\S]*?)"\s*$)?/gm;
123
+ let m = lineRe.exec(section[1]);
124
+ while (m !== null) {
125
+ out.push({
126
+ type: m[1],
127
+ ref: m[2],
128
+ quote: m[3],
129
+ });
130
+ m = lineRe.exec(section[1]);
131
+ }
132
+ return out;
133
+ }
134
+ function parseAmbiguousList(chunk) {
135
+ const section = chunk.match(/\*\*Ambiguous[^*]*\*\*\s*\n([\s\S]*?)(?=\n\n\*\*[A-Z]|\n\n```|\n## |$)/);
136
+ if (!section)
137
+ return [];
138
+ const out = [];
139
+ const lineRe = /^-\s+§([^:]+):\s+(.+)$/gm;
140
+ let m = lineRe.exec(section[1]);
141
+ while (m !== null) {
142
+ out.push({ section: m[1].trim(), reason: m[2].trim() });
143
+ m = lineRe.exec(section[1]);
144
+ }
145
+ return out;
146
+ }
147
+ function parseDiffBlock(chunk) {
148
+ const m = chunk.match(/\*\*Diff:\*\*\s*\n```diff\n([\s\S]*?)\n```/);
149
+ return m ? m[1] : undefined;
150
+ }
151
+ //# sourceMappingURL=revise-plan-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"revise-plan-service.js","sourceRoot":"","sources":["../../src/services/revise-plan-service.ts"],"names":[],"mappings":"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"}