openplanr 1.2.6 → 1.2.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 (149) hide show
  1. package/README.md +54 -1
  2. package/dist/ai/prompts/prompt-builder.d.ts +48 -0
  3. package/dist/ai/prompts/prompt-builder.d.ts.map +1 -1
  4. package/dist/ai/prompts/prompt-builder.js +57 -1
  5. package/dist/ai/prompts/prompt-builder.js.map +1 -1
  6. package/dist/ai/prompts/system-prompts.d.ts +23 -0
  7. package/dist/ai/prompts/system-prompts.d.ts.map +1 -1
  8. package/dist/ai/prompts/system-prompts.js +98 -0
  9. package/dist/ai/prompts/system-prompts.js.map +1 -1
  10. package/dist/ai/schemas/ai-response-schemas.d.ts +68 -0
  11. package/dist/ai/schemas/ai-response-schemas.d.ts.map +1 -1
  12. package/dist/ai/schemas/ai-response-schemas.js +81 -0
  13. package/dist/ai/schemas/ai-response-schemas.js.map +1 -1
  14. package/dist/ai/types.d.ts +2 -0
  15. package/dist/ai/types.d.ts.map +1 -1
  16. package/dist/ai/types.js +2 -0
  17. package/dist/ai/types.js.map +1 -1
  18. package/dist/cli/commands/context.d.ts +6 -0
  19. package/dist/cli/commands/context.d.ts.map +1 -0
  20. package/dist/cli/commands/context.js +45 -0
  21. package/dist/cli/commands/context.js.map +1 -0
  22. package/dist/cli/commands/export.d.ts.map +1 -1
  23. package/dist/cli/commands/export.js +8 -0
  24. package/dist/cli/commands/export.js.map +1 -1
  25. package/dist/cli/commands/report-linter.d.ts +6 -0
  26. package/dist/cli/commands/report-linter.d.ts.map +1 -0
  27. package/dist/cli/commands/report-linter.js +61 -0
  28. package/dist/cli/commands/report-linter.js.map +1 -0
  29. package/dist/cli/commands/report.d.ts +6 -0
  30. package/dist/cli/commands/report.d.ts.map +1 -0
  31. package/dist/cli/commands/report.js +150 -0
  32. package/dist/cli/commands/report.js.map +1 -0
  33. package/dist/cli/commands/revise.d.ts +23 -0
  34. package/dist/cli/commands/revise.d.ts.map +1 -0
  35. package/dist/cli/commands/revise.js +502 -0
  36. package/dist/cli/commands/revise.js.map +1 -0
  37. package/dist/cli/commands/story.d.ts.map +1 -1
  38. package/dist/cli/commands/story.js +31 -0
  39. package/dist/cli/commands/story.js.map +1 -1
  40. package/dist/cli/commands/voice.d.ts +6 -0
  41. package/dist/cli/commands/voice.d.ts.map +1 -0
  42. package/dist/cli/commands/voice.js +64 -0
  43. package/dist/cli/commands/voice.js.map +1 -0
  44. package/dist/cli/index.js +10 -0
  45. package/dist/cli/index.js.map +1 -1
  46. package/dist/models/schema.d.ts +63 -0
  47. package/dist/models/schema.d.ts.map +1 -1
  48. package/dist/models/schema.js +31 -0
  49. package/dist/models/schema.js.map +1 -1
  50. package/dist/models/types.d.ts +280 -0
  51. package/dist/models/types.d.ts.map +1 -1
  52. package/dist/services/atomic-write-service.d.ts +41 -0
  53. package/dist/services/atomic-write-service.d.ts.map +1 -0
  54. package/dist/services/atomic-write-service.js +87 -0
  55. package/dist/services/atomic-write-service.js.map +1 -0
  56. package/dist/services/audit-log-service.d.ts +50 -0
  57. package/dist/services/audit-log-service.d.ts.map +1 -0
  58. package/dist/services/audit-log-service.js +213 -0
  59. package/dist/services/audit-log-service.js.map +1 -0
  60. package/dist/services/cascade-service.d.ts +62 -0
  61. package/dist/services/cascade-service.d.ts.map +1 -0
  62. package/dist/services/cascade-service.js +189 -0
  63. package/dist/services/cascade-service.js.map +1 -0
  64. package/dist/services/context-pack-service.d.ts +12 -0
  65. package/dist/services/context-pack-service.d.ts.map +1 -0
  66. package/dist/services/context-pack-service.js +155 -0
  67. package/dist/services/context-pack-service.js.map +1 -0
  68. package/dist/services/diff-service.d.ts +18 -0
  69. package/dist/services/diff-service.d.ts.map +1 -0
  70. package/dist/services/diff-service.js +35 -0
  71. package/dist/services/diff-service.js.map +1 -0
  72. package/dist/services/distribution-service.d.ts +18 -0
  73. package/dist/services/distribution-service.d.ts.map +1 -0
  74. package/dist/services/distribution-service.js +104 -0
  75. package/dist/services/distribution-service.js.map +1 -0
  76. package/dist/services/evidence-service.d.ts +17 -0
  77. package/dist/services/evidence-service.d.ts.map +1 -0
  78. package/dist/services/evidence-service.js +85 -0
  79. package/dist/services/evidence-service.js.map +1 -0
  80. package/dist/services/evidence-verifier.d.ts +71 -0
  81. package/dist/services/evidence-verifier.d.ts.map +1 -0
  82. package/dist/services/evidence-verifier.js +171 -0
  83. package/dist/services/evidence-verifier.js.map +1 -0
  84. package/dist/services/git-service.d.ts +60 -0
  85. package/dist/services/git-service.d.ts.map +1 -0
  86. package/dist/services/git-service.js +137 -0
  87. package/dist/services/git-service.js.map +1 -0
  88. package/dist/services/github-service.d.ts +28 -1
  89. package/dist/services/github-service.d.ts.map +1 -1
  90. package/dist/services/github-service.js +95 -0
  91. package/dist/services/github-service.js.map +1 -1
  92. package/dist/services/graph-integrity.d.ts +36 -0
  93. package/dist/services/graph-integrity.d.ts.map +1 -0
  94. package/dist/services/graph-integrity.js +54 -0
  95. package/dist/services/graph-integrity.js.map +1 -0
  96. package/dist/services/prompt-service.d.ts +18 -0
  97. package/dist/services/prompt-service.d.ts.map +1 -1
  98. package/dist/services/prompt-service.js +47 -0
  99. package/dist/services/prompt-service.js.map +1 -1
  100. package/dist/services/report-linter-service.d.ts +10 -0
  101. package/dist/services/report-linter-service.d.ts.map +1 -0
  102. package/dist/services/report-linter-service.js +95 -0
  103. package/dist/services/report-linter-service.js.map +1 -0
  104. package/dist/services/report-service.d.ts +37 -0
  105. package/dist/services/report-service.d.ts.map +1 -0
  106. package/dist/services/report-service.js +173 -0
  107. package/dist/services/report-service.js.map +1 -0
  108. package/dist/services/revise-cache-service.d.ts +46 -0
  109. package/dist/services/revise-cache-service.d.ts.map +1 -0
  110. package/dist/services/revise-cache-service.js +88 -0
  111. package/dist/services/revise-cache-service.js.map +1 -0
  112. package/dist/services/revise-service.d.ts +108 -0
  113. package/dist/services/revise-service.d.ts.map +1 -0
  114. package/dist/services/revise-service.js +249 -0
  115. package/dist/services/revise-service.js.map +1 -0
  116. package/dist/services/standup-parser.d.ts +21 -0
  117. package/dist/services/standup-parser.d.ts.map +1 -0
  118. package/dist/services/standup-parser.js +104 -0
  119. package/dist/services/standup-parser.js.map +1 -0
  120. package/dist/services/story-standup-service.d.ts +7 -0
  121. package/dist/services/story-standup-service.d.ts.map +1 -0
  122. package/dist/services/story-standup-service.js +27 -0
  123. package/dist/services/story-standup-service.js.map +1 -0
  124. package/dist/services/template-sections.d.ts +28 -0
  125. package/dist/services/template-sections.d.ts.map +1 -0
  126. package/dist/services/template-sections.js +55 -0
  127. package/dist/services/template-sections.js.map +1 -0
  128. package/dist/services/template-service.d.ts.map +1 -1
  129. package/dist/services/template-service.js +1 -0
  130. package/dist/services/template-service.js.map +1 -1
  131. package/dist/services/voice-service.d.ts +12 -0
  132. package/dist/services/voice-service.d.ts.map +1 -0
  133. package/dist/services/voice-service.js +42 -0
  134. package/dist/services/voice-service.js.map +1 -0
  135. package/dist/templates/export/planning-report.html.hbs +10 -0
  136. package/dist/templates/export/planning-report.md.hbs +11 -0
  137. package/dist/templates/linter/linter-config.json.hbs +13 -0
  138. package/dist/templates/reports/executive.md.hbs +28 -0
  139. package/dist/templates/reports/release-notes.md.hbs +37 -0
  140. package/dist/templates/reports/retrospective.md.hbs +36 -0
  141. package/dist/templates/reports/sprint.md.hbs +91 -0
  142. package/dist/templates/reports/standup.md.hbs +27 -0
  143. package/dist/templates/reports/weekly.md.hbs +42 -0
  144. package/dist/templates/voice/standup.md.hbs +20 -0
  145. package/dist/utils/diff.d.ts +26 -0
  146. package/dist/utils/diff.d.ts.map +1 -0
  147. package/dist/utils/diff.js +143 -0
  148. package/dist/utils/diff.js.map +1 -0
  149. package/package.json +1 -1
@@ -0,0 +1,189 @@
1
+ /**
2
+ * Cascade execution for `planr revise` (EPIC-003, FEAT-012).
3
+ *
4
+ * Responsibilities:
5
+ *
6
+ * 1. **Build cascade order** — top-down: epic → features → stories → tasks.
7
+ * The artifact hierarchy is a strict tree; no cycle detection is needed.
8
+ * 2. **Execute the cascade** — for each artifact in order, call the
9
+ * caller-provided `processOne` closure. The cascade stops on
10
+ * SIGINT, `[q]uit`, or an unrecoverable agent error, and always
11
+ * flushes audit entries immediately so an interrupted run leaves an
12
+ * accurate record.
13
+ * 3. **Progress tracking** — emits a `CascadeProgress` snapshot before
14
+ * each artifact, with a rolling ETA.
15
+ *
16
+ * This service owns NO rollback logic. Partial cascades that break the
17
+ * artifact graph are the concern of FEAT-013's post-flight rollback.
18
+ */
19
+ import { logger } from '../utils/logger.js';
20
+ import { listArtifacts, readArtifact } from './artifact-service.js';
21
+ // ---------------------------------------------------------------------------
22
+ // Cascade order (§1.0)
23
+ // ---------------------------------------------------------------------------
24
+ /**
25
+ * Resolve the cascade plan for a root artifact, walking its descendants in
26
+ * top-down order. For an epic root, the plan is:
27
+ * EPIC → [features under epic] → [stories under those features] → [tasks under those stories]
28
+ * For a feature root, the EPIC level is empty and features contain only the root, etc.
29
+ */
30
+ export async function buildCascadeOrder(projectDir, config, rootType, rootId) {
31
+ const levels = [
32
+ { type: 'epic', label: 'epic', artifactIds: [] },
33
+ { type: 'feature', label: 'features', artifactIds: [] },
34
+ { type: 'story', label: 'stories', artifactIds: [] },
35
+ { type: 'task', label: 'tasks', artifactIds: [] },
36
+ ];
37
+ if (rootType === 'epic') {
38
+ levels[0].artifactIds = [rootId];
39
+ const features = await listArtifacts(projectDir, config, 'feature');
40
+ for (const f of features) {
41
+ const featureArtifact = await readArtifact(projectDir, config, 'feature', f.id);
42
+ if (featureArtifact?.data.epicId === rootId) {
43
+ levels[1].artifactIds.push(f.id);
44
+ }
45
+ }
46
+ for (const featureId of levels[1].artifactIds) {
47
+ const stories = await listArtifacts(projectDir, config, 'story');
48
+ for (const s of stories) {
49
+ const storyArtifact = await readArtifact(projectDir, config, 'story', s.id);
50
+ if (storyArtifact?.data.featureId === featureId) {
51
+ levels[2].artifactIds.push(s.id);
52
+ }
53
+ }
54
+ }
55
+ for (const storyId of levels[2].artifactIds) {
56
+ const tasks = await listArtifacts(projectDir, config, 'task');
57
+ for (const t of tasks) {
58
+ const taskArtifact = await readArtifact(projectDir, config, 'task', t.id);
59
+ if (taskArtifact?.data.storyId === storyId) {
60
+ levels[3].artifactIds.push(t.id);
61
+ }
62
+ }
63
+ }
64
+ }
65
+ else if (rootType === 'feature') {
66
+ levels[1].artifactIds = [rootId];
67
+ const stories = await listArtifacts(projectDir, config, 'story');
68
+ for (const s of stories) {
69
+ const storyArtifact = await readArtifact(projectDir, config, 'story', s.id);
70
+ if (storyArtifact?.data.featureId === rootId) {
71
+ levels[2].artifactIds.push(s.id);
72
+ }
73
+ }
74
+ for (const storyId of levels[2].artifactIds) {
75
+ const tasks = await listArtifacts(projectDir, config, 'task');
76
+ for (const t of tasks) {
77
+ const taskArtifact = await readArtifact(projectDir, config, 'task', t.id);
78
+ if (taskArtifact?.data.storyId === storyId) {
79
+ levels[3].artifactIds.push(t.id);
80
+ }
81
+ }
82
+ }
83
+ }
84
+ else if (rootType === 'story') {
85
+ levels[2].artifactIds = [rootId];
86
+ const tasks = await listArtifacts(projectDir, config, 'task');
87
+ for (const t of tasks) {
88
+ const taskArtifact = await readArtifact(projectDir, config, 'task', t.id);
89
+ if (taskArtifact?.data.storyId === rootId) {
90
+ levels[3].artifactIds.push(t.id);
91
+ }
92
+ }
93
+ }
94
+ else if (rootType === 'task') {
95
+ levels[3].artifactIds = [rootId];
96
+ }
97
+ else {
98
+ // Non-hierarchy types (quick, backlog, sprint, adr, checklist) — cascade
99
+ // is a no-op scope that only processes the root. We stash the id at the
100
+ // tasks level to avoid leaving the plan empty.
101
+ levels[3].artifactIds = [rootId];
102
+ }
103
+ const orderedIds = levels.flatMap((l) => l.artifactIds);
104
+ return { rootId, rootType, levels, orderedIds };
105
+ }
106
+ /**
107
+ * Drive the cascade plan through the provided processor. Installs a SIGINT
108
+ * handler for the duration of the run; on Ctrl+C it waits for the current
109
+ * artifact to finish (so no half-written files) and then stops. The SIGINT
110
+ * handler is removed on completion whether or not it fired.
111
+ */
112
+ export async function executeCascade(options) {
113
+ const { plan, processor } = options;
114
+ const signalTarget = options.signalTarget ?? process;
115
+ const total = plan.orderedIds.length;
116
+ let completed = 0;
117
+ let interruptedByUser = false;
118
+ const sigintHandler = () => {
119
+ interruptedByUser = true;
120
+ logger.warn('\nSIGINT received — cascade will stop after current artifact completes.');
121
+ };
122
+ signalTarget.once('SIGINT', sigintHandler);
123
+ const started = Date.now();
124
+ try {
125
+ for (const level of plan.levels) {
126
+ for (const artifactId of level.artifactIds) {
127
+ if (interruptedByUser) {
128
+ return {
129
+ completed,
130
+ total,
131
+ interrupted: { reason: 'sigint', atArtifactId: artifactId },
132
+ };
133
+ }
134
+ const progress = {
135
+ completed,
136
+ total,
137
+ currentArtifactId: artifactId,
138
+ currentLevelLabel: level.label,
139
+ etaSeconds: estimateEta(started, completed, total),
140
+ };
141
+ options.onProgress?.(progress);
142
+ let outcome;
143
+ try {
144
+ outcome = await processor({
145
+ artifactId,
146
+ levelLabel: level.label,
147
+ progress,
148
+ });
149
+ }
150
+ catch (err) {
151
+ logger.error(`Cascade aborted at ${artifactId}: ${err instanceof Error ? err.message : String(err)}`);
152
+ return {
153
+ completed,
154
+ total,
155
+ interrupted: { reason: 'agent_error', atArtifactId: artifactId },
156
+ };
157
+ }
158
+ completed++;
159
+ if (!outcome.continue) {
160
+ return {
161
+ completed,
162
+ total,
163
+ interrupted: {
164
+ reason: outcome.stopReason === 'q' ? 'q' : 'agent_error',
165
+ atArtifactId: artifactId,
166
+ },
167
+ };
168
+ }
169
+ }
170
+ }
171
+ return { completed, total };
172
+ }
173
+ finally {
174
+ signalTarget.removeListener('SIGINT', sigintHandler);
175
+ }
176
+ }
177
+ /**
178
+ * Estimate seconds remaining based on observed pace. Returns null for the
179
+ * first couple of samples so the UI doesn't print wildly unstable numbers.
180
+ */
181
+ function estimateEta(startedMs, completed, total) {
182
+ if (completed < 2 || total === 0)
183
+ return null;
184
+ const elapsed = (Date.now() - startedMs) / 1000;
185
+ const perItem = elapsed / completed;
186
+ const remaining = Math.max(0, total - completed);
187
+ return Math.round(perItem * remaining);
188
+ }
189
+ //# sourceMappingURL=cascade-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cascade-service.js","sourceRoot":"","sources":["../../src/services/cascade-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Assemble stakeholder report context from `.planr/` artifacts and optional GitHub signals.
3
+ */
4
+ import type { OpenPlanrConfig, StakeholderReportContext, StakeholderReportType } from '../models/types.js';
5
+ export interface BuildContextOptions {
6
+ reportType: StakeholderReportType;
7
+ days: number;
8
+ sprintId?: string;
9
+ includeGitHub: boolean;
10
+ }
11
+ export declare function buildStakeholderReportContext(projectDir: string, config: OpenPlanrConfig, opts: BuildContextOptions): Promise<StakeholderReportContext>;
12
+ //# sourceMappingURL=context-pack-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-pack-service.d.ts","sourceRoot":"","sources":["../../src/services/context-pack-service.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAEV,eAAe,EAIf,wBAAwB,EACxB,qBAAqB,EACtB,MAAM,oBAAoB,CAAC;AAI5B,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,qBAAqB,CAAC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,OAAO,CAAC;CACxB;AAaD,wBAAsB,6BAA6B,CACjD,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,mBAAmB,GACxB,OAAO,CAAC,wBAAwB,CAAC,CAmHnC"}
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Assemble stakeholder report context from `.planr/` artifacts and optional GitHub signals.
3
+ */
4
+ import { listArtifacts, readArtifact } from './artifact-service.js';
5
+ import { fetchRecentCommits, fetchRecentPullRequests } from './github-service.js';
6
+ function statusOf(data) {
7
+ const s = data.status ?? data.Status;
8
+ return typeof s === 'string' ? s : 'unknown';
9
+ }
10
+ function titleOf(meta, data) {
11
+ const t = data.title;
12
+ if (typeof t === 'string' && t.trim())
13
+ return t;
14
+ return meta.title;
15
+ }
16
+ export async function buildStakeholderReportContext(projectDir, config, opts) {
17
+ const generatedAt = new Date().toISOString();
18
+ const epicsMeta = await listArtifacts(projectDir, config, 'epic');
19
+ const featuresMeta = await listArtifacts(projectDir, config, 'feature');
20
+ const storiesMeta = await listArtifacts(projectDir, config, 'story');
21
+ const tasksMeta = await listArtifacts(projectDir, config, 'task');
22
+ const epics = [];
23
+ for (const m of epicsMeta) {
24
+ const a = await readArtifact(projectDir, config, 'epic', m.id);
25
+ const data = (a?.data ?? {});
26
+ epics.push({
27
+ id: m.id,
28
+ title: titleOf(m, data),
29
+ status: statusOf(data),
30
+ type: 'epic',
31
+ });
32
+ }
33
+ const features = [];
34
+ for (const m of featuresMeta) {
35
+ const a = await readArtifact(projectDir, config, 'feature', m.id);
36
+ const data = (a?.data ?? {});
37
+ features.push({
38
+ id: m.id,
39
+ title: titleOf(m, data),
40
+ status: statusOf(data),
41
+ type: 'feature',
42
+ });
43
+ }
44
+ const stories = [];
45
+ for (const m of storiesMeta) {
46
+ const a = await readArtifact(projectDir, config, 'story', m.id);
47
+ const data = (a?.data ?? {});
48
+ stories.push({
49
+ id: m.id,
50
+ title: titleOf(m, data),
51
+ status: statusOf(data),
52
+ type: 'story',
53
+ });
54
+ }
55
+ const tasks = [];
56
+ for (const m of tasksMeta) {
57
+ const a = await readArtifact(projectDir, config, 'task', m.id);
58
+ const data = (a?.data ?? {});
59
+ tasks.push({
60
+ id: m.id,
61
+ title: titleOf(m, data),
62
+ status: statusOf(data),
63
+ type: 'task',
64
+ });
65
+ }
66
+ let sprint;
67
+ if (opts.sprintId) {
68
+ const s = await readArtifact(projectDir, config, 'sprint', opts.sprintId);
69
+ if (s) {
70
+ const data = s.data;
71
+ const rawGoals = data.goals;
72
+ const goals = Array.isArray(rawGoals) ? rawGoals.map(String) : [];
73
+ const rawTaskIds = data.taskIds;
74
+ const taskIds = Array.isArray(rawTaskIds) ? rawTaskIds.map(String) : [];
75
+ sprint = {
76
+ sprintId: opts.sprintId,
77
+ name: String(data.name ?? opts.sprintId),
78
+ status: statusOf(data),
79
+ startDate: String(data.startDate ?? ''),
80
+ endDate: String(data.endDate ?? ''),
81
+ goals,
82
+ taskIds,
83
+ };
84
+ }
85
+ }
86
+ let github;
87
+ let noGitHub = !opts.includeGitHub;
88
+ if (opts.includeGitHub) {
89
+ const [cRes, pRes] = await Promise.all([
90
+ fetchRecentCommits({ days: opts.days, limit: 30 }),
91
+ fetchRecentPullRequests({ days: opts.days, limit: 20 }),
92
+ ]);
93
+ const warn = [cRes.warning, pRes.warning].filter(Boolean).join(' ');
94
+ github = {
95
+ commits: cRes.commits,
96
+ pullRequests: pRes.pullRequests,
97
+ warning: warn || undefined,
98
+ fetchedAt: generatedAt,
99
+ };
100
+ noGitHub = Boolean(warn) && cRes.commits.length === 0 && pRes.pullRequests.length === 0;
101
+ }
102
+ const doneStories = stories.filter((x) => /done|closed/i.test(x.status));
103
+ const anchorStories = doneStories.length > 0 ? doneStories.slice(0, 15) : stories.slice(0, 15);
104
+ const evidence = buildEvidenceList(github, anchorStories);
105
+ const branding = config.reports;
106
+ return {
107
+ projectName: config.projectName,
108
+ generatedAt,
109
+ reportType: opts.reportType,
110
+ daysLookback: opts.days,
111
+ sprint,
112
+ artifacts: { epics, features, stories, tasks },
113
+ github,
114
+ branding,
115
+ placeholders: {
116
+ noSprint: !sprint,
117
+ noGitHub: noGitHub,
118
+ noStoriesCompleted: doneStories.length === 0,
119
+ },
120
+ evidence,
121
+ };
122
+ }
123
+ function buildEvidenceList(github, stories) {
124
+ const out = [];
125
+ for (const s of stories) {
126
+ out.push({
127
+ id: `artifact-${s.id}`,
128
+ kind: 'artifact',
129
+ label: `${s.id}: ${s.title}`,
130
+ detail: `Status: ${s.status}`,
131
+ });
132
+ }
133
+ if (github) {
134
+ for (const c of github.commits.slice(0, 20)) {
135
+ out.push({
136
+ id: `commit-${c.shortSha}`,
137
+ kind: 'commit',
138
+ label: c.message,
139
+ url: c.url,
140
+ detail: `${c.authorLogin} · ${c.committedDate}`,
141
+ });
142
+ }
143
+ for (const p of github.pullRequests.slice(0, 15)) {
144
+ out.push({
145
+ id: `pr-${p.number}`,
146
+ kind: 'pull_request',
147
+ label: `PR #${p.number}: ${p.title}`,
148
+ url: p.url,
149
+ detail: `${p.state} · ${p.authorLogin}`,
150
+ });
151
+ }
152
+ }
153
+ return out;
154
+ }
155
+ //# sourceMappingURL=context-pack-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-pack-service.js","sourceRoot":"","sources":["../../src/services/context-pack-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Colored diff preview for revise (EPIC-003, FEAT-011 §4.2).
3
+ *
4
+ * Wraps the pure `unifiedDiff` utility with chalk formatting. The returned
5
+ * string is what the CLI prints before asking the user to apply / skip /
6
+ * edit / re-view / quit.
7
+ */
8
+ import { type UnifiedDiffOptions } from '../utils/diff.js';
9
+ export interface RenderDiffOptions extends UnifiedDiffOptions {
10
+ /** Set to false to skip ANSI color codes (useful for tests / non-TTY output). */
11
+ color?: boolean;
12
+ }
13
+ /**
14
+ * Produce a unified diff between `oldText` and `newText`, color-coded for
15
+ * terminal display. Returns the empty string when the two are identical.
16
+ */
17
+ export declare function renderDiff(oldText: string, newText: string, options?: RenderDiffOptions): string;
18
+ //# sourceMappingURL=diff-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-service.d.ts","sourceRoot":"","sources":["../../src/services/diff-service.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,KAAK,kBAAkB,EAAe,MAAM,kBAAkB,CAAC;AAExE,MAAM,WAAW,iBAAkB,SAAQ,kBAAkB;IAC3D,iFAAiF;IACjF,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,UAAU,CACxB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,iBAAsB,GAC9B,MAAM,CAeR"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Colored diff preview for revise (EPIC-003, FEAT-011 §4.2).
3
+ *
4
+ * Wraps the pure `unifiedDiff` utility with chalk formatting. The returned
5
+ * string is what the CLI prints before asking the user to apply / skip /
6
+ * edit / re-view / quit.
7
+ */
8
+ import chalk from 'chalk';
9
+ import { unifiedDiff } from '../utils/diff.js';
10
+ /**
11
+ * Produce a unified diff between `oldText` and `newText`, color-coded for
12
+ * terminal display. Returns the empty string when the two are identical.
13
+ */
14
+ export function renderDiff(oldText, newText, options = {}) {
15
+ const raw = unifiedDiff(oldText, newText, options);
16
+ if (raw.length === 0)
17
+ return '';
18
+ if (options.color === false)
19
+ return raw;
20
+ return raw
21
+ .split('\n')
22
+ .map((line) => {
23
+ if (line.startsWith('+++') || line.startsWith('---'))
24
+ return chalk.bold(line);
25
+ if (line.startsWith('@@'))
26
+ return chalk.cyan(line);
27
+ if (line.startsWith('+'))
28
+ return chalk.green(line);
29
+ if (line.startsWith('-'))
30
+ return chalk.red(line);
31
+ return chalk.dim(line);
32
+ })
33
+ .join('\n');
34
+ }
35
+ //# sourceMappingURL=diff-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-service.js","sourceRoot":"","sources":["../../src/services/diff-service.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAA2B,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAOxE;;;GAGG;AACH,MAAM,UAAU,UAAU,CACxB,OAAe,EACf,OAAe,EACf,UAA6B,EAAE;IAE/B,MAAM,GAAG,GAAG,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IACnD,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAChC,IAAI,OAAO,CAAC,KAAK,KAAK,KAAK;QAAE,OAAO,GAAG,CAAC;IAExC,OAAO,GAAG;SACP,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACZ,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9E,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnD,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACnD,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACjD,OAAO,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Delivery channels for stakeholder reports (GitHub issue push; Slack webhooks; email stub).
3
+ */
4
+ import type { DistributionResult, OpenPlanrConfig } from '../models/types.js';
5
+ export declare function pushReportAsGitHubIssue(args: {
6
+ title: string;
7
+ body: string;
8
+ dryRun: boolean;
9
+ }): Promise<DistributionResult>;
10
+ export declare function pushReportToSlack(config: OpenPlanrConfig, markdown: string, args?: {
11
+ dryRun?: boolean;
12
+ }): Promise<DistributionResult>;
13
+ export declare function pushReportByEmail(_config: OpenPlanrConfig, _args: {
14
+ to: string[];
15
+ subject: string;
16
+ body: string;
17
+ }): Promise<DistributionResult>;
18
+ //# sourceMappingURL=distribution-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"distribution-service.d.ts","sourceRoot":"","sources":["../../src/services/distribution-service.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAW9E,wBAAsB,uBAAuB,CAAC,IAAI,EAAE;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;CACjB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAwB9B;AAED,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,eAAe,EACvB,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GAC1B,OAAO,CAAC,kBAAkB,CAAC,CA0D7B;AAED,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,eAAe,EACxB,KAAK,EAAE;IAAE,EAAE,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACrD,OAAO,CAAC,kBAAkB,CAAC,CAc7B"}
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Delivery channels for stakeholder reports (GitHub issue push; Slack webhooks; email stub).
3
+ */
4
+ import { createIssue, ensureLabel } from './github-service.js';
5
+ const SLACK_TEXT_MAX = 12000;
6
+ function truncateForSlack(text) {
7
+ const t = text.trim();
8
+ if (t.length <= SLACK_TEXT_MAX)
9
+ return t;
10
+ return `${t.slice(0, SLACK_TEXT_MAX)}\n\n…(truncated; full report saved locally)`;
11
+ }
12
+ export async function pushReportAsGitHubIssue(args) {
13
+ if (args.dryRun) {
14
+ return {
15
+ channel: 'github_issue',
16
+ ok: true,
17
+ message: 'Dry run: would create GitHub issue with stakeholder report body.',
18
+ };
19
+ }
20
+ try {
21
+ await ensureLabel('planr:report');
22
+ const { url } = await createIssue(args.title, args.body, ['planr:report']);
23
+ return {
24
+ channel: 'github_issue',
25
+ ok: true,
26
+ message: 'Created GitHub issue with report.',
27
+ url,
28
+ };
29
+ }
30
+ catch (err) {
31
+ return {
32
+ channel: 'github_issue',
33
+ ok: false,
34
+ message: err.message,
35
+ };
36
+ }
37
+ }
38
+ export async function pushReportToSlack(config, markdown, args) {
39
+ const url = config.distribution?.slackWebhookUrl;
40
+ if (args?.dryRun) {
41
+ if (!url) {
42
+ return {
43
+ channel: 'slack',
44
+ ok: true,
45
+ message: 'Dry run: no Slack webhook in config (no POST). Add `distribution.slackWebhookUrl` to .planr/config.json, then run without --dry-run to send.',
46
+ };
47
+ }
48
+ return {
49
+ channel: 'slack',
50
+ ok: true,
51
+ message: `Dry run: would POST ~${Math.min(markdown.length, SLACK_TEXT_MAX)} chars to your Slack webhook (no request sent).`,
52
+ };
53
+ }
54
+ if (!url) {
55
+ return {
56
+ channel: 'slack',
57
+ ok: false,
58
+ message: 'Slack is not configured. Set `distribution.slackWebhookUrl` in .planr/config.json (or use --push github).',
59
+ };
60
+ }
61
+ try {
62
+ const payload = { text: truncateForSlack(markdown) };
63
+ const res = await fetch(url, {
64
+ method: 'POST',
65
+ headers: { 'Content-Type': 'application/json' },
66
+ body: JSON.stringify(payload),
67
+ });
68
+ const bodyText = await res.text().catch(() => '');
69
+ if (!res.ok) {
70
+ return {
71
+ channel: 'slack',
72
+ ok: false,
73
+ message: `Slack webhook failed (${res.status}): ${bodyText || res.statusText}. Check the webhook URL and app permissions.`,
74
+ };
75
+ }
76
+ return {
77
+ channel: 'slack',
78
+ ok: true,
79
+ message: 'Posted report to Slack.',
80
+ };
81
+ }
82
+ catch (err) {
83
+ return {
84
+ channel: 'slack',
85
+ ok: false,
86
+ message: `Slack request failed: ${err.message}`,
87
+ };
88
+ }
89
+ }
90
+ export async function pushReportByEmail(_config, _args) {
91
+ if (!_config.distribution?.emailSmtpHost) {
92
+ return {
93
+ channel: 'email',
94
+ ok: false,
95
+ message: 'Email is not configured. Set `distribution.emailSmtpHost` and related fields in .planr/config.json.',
96
+ };
97
+ }
98
+ return {
99
+ channel: 'email',
100
+ ok: false,
101
+ message: 'SMTP delivery is not implemented in this build.',
102
+ };
103
+ }
104
+ //# sourceMappingURL=distribution-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"distribution-service.js","sourceRoot":"","sources":["../../src/services/distribution-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Evidence linking and validation for stakeholder reports.
3
+ */
4
+ import type { ClaimValidationResult, EvidenceSummary, ReportEvidenceItem, StakeholderReportType } from '../models/types.js';
5
+ export declare function countEvidenceAnchors(markdown: string): number;
6
+ export interface ValidateClaimsOptions {
7
+ /** Included for forward-compatible per-report tuning; reserved for future use. */
8
+ reportType?: StakeholderReportType;
9
+ }
10
+ export declare function validateClaimsHaveAnchors(markdown: string, minAnchors: number, options?: ValidateClaimsOptions): ClaimValidationResult[];
11
+ export declare function validateRemoteEvidence(items: ReportEvidenceItem[]): Promise<{
12
+ inaccessible: ReportEvidenceItem[];
13
+ repoOk: boolean;
14
+ repoMessage: string;
15
+ }>;
16
+ export declare function summarizeEvidenceItem(item: ReportEvidenceItem): EvidenceSummary;
17
+ //# sourceMappingURL=evidence-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evidence-service.d.ts","sourceRoot":"","sources":["../../src/services/evidence-service.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,qBAAqB,EACrB,eAAe,EACf,kBAAkB,EAClB,qBAAqB,EACtB,MAAM,oBAAoB,CAAC;AAM5B,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAI7D;AAED,MAAM,WAAW,qBAAqB;IACpC,kFAAkF;IAClF,UAAU,CAAC,EAAE,qBAAqB,CAAC;CACpC;AAcD,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,qBAAqB,GAC9B,qBAAqB,EAAE,CAkCzB;AAED,wBAAsB,sBAAsB,CAAC,KAAK,EAAE,kBAAkB,EAAE,GAAG,OAAO,CAAC;IACjF,YAAY,EAAE,kBAAkB,EAAE,CAAC;IACnC,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC,CAeD;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,kBAAkB,GAAG,eAAe,CAM/E"}