openplanr 1.2.7 → 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.
- package/README.md +34 -1
- package/dist/ai/prompts/prompt-builder.d.ts +48 -0
- package/dist/ai/prompts/prompt-builder.d.ts.map +1 -1
- package/dist/ai/prompts/prompt-builder.js +57 -1
- package/dist/ai/prompts/prompt-builder.js.map +1 -1
- package/dist/ai/prompts/system-prompts.d.ts +23 -0
- package/dist/ai/prompts/system-prompts.d.ts.map +1 -1
- package/dist/ai/prompts/system-prompts.js +98 -0
- package/dist/ai/prompts/system-prompts.js.map +1 -1
- package/dist/ai/schemas/ai-response-schemas.d.ts +68 -0
- package/dist/ai/schemas/ai-response-schemas.d.ts.map +1 -1
- package/dist/ai/schemas/ai-response-schemas.js +81 -0
- package/dist/ai/schemas/ai-response-schemas.js.map +1 -1
- package/dist/ai/types.d.ts +2 -0
- package/dist/ai/types.d.ts.map +1 -1
- package/dist/ai/types.js +2 -0
- package/dist/ai/types.js.map +1 -1
- package/dist/cli/commands/revise.d.ts +23 -0
- package/dist/cli/commands/revise.d.ts.map +1 -0
- package/dist/cli/commands/revise.js +502 -0
- package/dist/cli/commands/revise.js.map +1 -0
- package/dist/cli/index.js +2 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/models/types.d.ts +120 -0
- package/dist/models/types.d.ts.map +1 -1
- package/dist/services/atomic-write-service.d.ts +41 -0
- package/dist/services/atomic-write-service.d.ts.map +1 -0
- package/dist/services/atomic-write-service.js +87 -0
- package/dist/services/atomic-write-service.js.map +1 -0
- package/dist/services/audit-log-service.d.ts +50 -0
- package/dist/services/audit-log-service.d.ts.map +1 -0
- package/dist/services/audit-log-service.js +213 -0
- package/dist/services/audit-log-service.js.map +1 -0
- package/dist/services/cascade-service.d.ts +62 -0
- package/dist/services/cascade-service.d.ts.map +1 -0
- package/dist/services/cascade-service.js +189 -0
- package/dist/services/cascade-service.js.map +1 -0
- package/dist/services/diff-service.d.ts +18 -0
- package/dist/services/diff-service.d.ts.map +1 -0
- package/dist/services/diff-service.js +35 -0
- package/dist/services/diff-service.js.map +1 -0
- package/dist/services/evidence-verifier.d.ts +71 -0
- package/dist/services/evidence-verifier.d.ts.map +1 -0
- package/dist/services/evidence-verifier.js +171 -0
- package/dist/services/evidence-verifier.js.map +1 -0
- package/dist/services/git-service.d.ts +60 -0
- package/dist/services/git-service.d.ts.map +1 -0
- package/dist/services/git-service.js +137 -0
- package/dist/services/git-service.js.map +1 -0
- package/dist/services/graph-integrity.d.ts +36 -0
- package/dist/services/graph-integrity.d.ts.map +1 -0
- package/dist/services/graph-integrity.js +54 -0
- package/dist/services/graph-integrity.js.map +1 -0
- package/dist/services/prompt-service.d.ts +18 -0
- package/dist/services/prompt-service.d.ts.map +1 -1
- package/dist/services/prompt-service.js +47 -0
- package/dist/services/prompt-service.js.map +1 -1
- package/dist/services/revise-cache-service.d.ts +46 -0
- package/dist/services/revise-cache-service.d.ts.map +1 -0
- package/dist/services/revise-cache-service.js +88 -0
- package/dist/services/revise-cache-service.js.map +1 -0
- package/dist/services/revise-service.d.ts +108 -0
- package/dist/services/revise-service.d.ts.map +1 -0
- package/dist/services/revise-service.js +249 -0
- package/dist/services/revise-service.js.map +1 -0
- package/dist/services/template-sections.d.ts +28 -0
- package/dist/services/template-sections.d.ts.map +1 -0
- package/dist/services/template-sections.js +55 -0
- package/dist/services/template-sections.js.map +1 -0
- package/dist/utils/diff.d.ts +26 -0
- package/dist/utils/diff.d.ts.map +1 -0
- package/dist/utils/diff.js +143 -0
- package/dist/utils/diff.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git integration for `planr revise` (EPIC-003, FEAT-011 + FEAT-013).
|
|
3
|
+
*
|
|
4
|
+
* Two responsibilities:
|
|
5
|
+
*
|
|
6
|
+
* 1. **Clean-tree gate (FEAT-011 §2.0):** revise refuses to run with a dirty
|
|
7
|
+
* working tree by default. Users can override with `--allow-dirty`, but
|
|
8
|
+
* post-flight rollback depends on a clean pre-run state, so the gate is
|
|
9
|
+
* the load-bearing safety net.
|
|
10
|
+
*
|
|
11
|
+
* 2. **Capture + rollback anchor (FEAT-013 §4.0):** before bulk writes,
|
|
12
|
+
* revise captures HEAD and the set of touched paths so a post-flight
|
|
13
|
+
* graph-integrity failure can restore via `git checkout`.
|
|
14
|
+
*
|
|
15
|
+
* All git operations use `execFile` (not shell), matching the pattern in
|
|
16
|
+
* github-service.ts. If git is not available or the project is not a git
|
|
17
|
+
* repo, clean-tree checks fail closed (revise refuses to run) unless
|
|
18
|
+
* --allow-dirty is passed, because without git there is no safety net.
|
|
19
|
+
*/
|
|
20
|
+
import { execFile } from 'node:child_process';
|
|
21
|
+
import { promisify } from 'node:util';
|
|
22
|
+
const execFileAsync = promisify(execFile);
|
|
23
|
+
const GIT_MAX_BUFFER = 10 * 1024 * 1024;
|
|
24
|
+
/**
|
|
25
|
+
* Inspect the working tree. Never throws — always returns a typed status so
|
|
26
|
+
* callers can render errors consistently.
|
|
27
|
+
*/
|
|
28
|
+
export async function inspectGitTree(projectDir) {
|
|
29
|
+
let head;
|
|
30
|
+
try {
|
|
31
|
+
const { stdout } = await execFileAsync('git', ['rev-parse', 'HEAD'], {
|
|
32
|
+
cwd: projectDir,
|
|
33
|
+
maxBuffer: GIT_MAX_BUFFER,
|
|
34
|
+
});
|
|
35
|
+
head = stdout.trim();
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
39
|
+
if (/not a git repository|fatal:.*repository/i.test(message)) {
|
|
40
|
+
return { kind: 'not-a-repo', reason: message };
|
|
41
|
+
}
|
|
42
|
+
if (/ENOENT|git: not found|command not found/i.test(message)) {
|
|
43
|
+
return { kind: 'git-missing', reason: message };
|
|
44
|
+
}
|
|
45
|
+
// Empty repo (no commits yet) also reaches here; treat it as not-a-repo
|
|
46
|
+
// for clean-tree gating purposes — there is no HEAD to roll back to.
|
|
47
|
+
if (/unknown revision|does not have any commits/i.test(message)) {
|
|
48
|
+
return { kind: 'not-a-repo', reason: 'git repository has no commits yet' };
|
|
49
|
+
}
|
|
50
|
+
return { kind: 'not-a-repo', reason: message };
|
|
51
|
+
}
|
|
52
|
+
const { stdout: porcelain } = await execFileAsync('git', ['status', '--porcelain'], {
|
|
53
|
+
cwd: projectDir,
|
|
54
|
+
maxBuffer: GIT_MAX_BUFFER,
|
|
55
|
+
});
|
|
56
|
+
if (porcelain.trim().length === 0) {
|
|
57
|
+
return { kind: 'clean', head };
|
|
58
|
+
}
|
|
59
|
+
const changedPaths = porcelain
|
|
60
|
+
.split('\n')
|
|
61
|
+
.filter((line) => line.length > 0)
|
|
62
|
+
.map((line) => line.slice(3).trim());
|
|
63
|
+
return { kind: 'dirty', head, changedPaths };
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* The clean-tree gate: clean → pass; dirty → pass only when --allow-dirty;
|
|
67
|
+
* missing git / not a repo → fail closed unless --allow-dirty was passed
|
|
68
|
+
* (because without git there is no post-flight rollback safety net).
|
|
69
|
+
*/
|
|
70
|
+
export async function checkCleanTree(projectDir, options) {
|
|
71
|
+
const status = await inspectGitTree(projectDir);
|
|
72
|
+
switch (status.kind) {
|
|
73
|
+
case 'clean':
|
|
74
|
+
return {
|
|
75
|
+
ok: true,
|
|
76
|
+
status,
|
|
77
|
+
message: `Working tree is clean at ${status.head.slice(0, 12)}.`,
|
|
78
|
+
};
|
|
79
|
+
case 'dirty':
|
|
80
|
+
if (options.allowDirty) {
|
|
81
|
+
return {
|
|
82
|
+
ok: true,
|
|
83
|
+
status,
|
|
84
|
+
message: `Working tree has ${status.changedPaths.length} uncommitted change(s); running with --allow-dirty. Post-flight rollback cannot restore these changes.`,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
ok: false,
|
|
89
|
+
status,
|
|
90
|
+
message: `Working tree has ${status.changedPaths.length} uncommitted change(s). Commit or stash them, or re-run with --allow-dirty (post-flight rollback cannot restore uncommitted work).`,
|
|
91
|
+
};
|
|
92
|
+
case 'not-a-repo':
|
|
93
|
+
if (options.allowDirty) {
|
|
94
|
+
return {
|
|
95
|
+
ok: true,
|
|
96
|
+
status,
|
|
97
|
+
message: `Not a git repository (${status.reason.trim()}); running with --allow-dirty. Post-flight rollback is disabled.`,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
ok: false,
|
|
102
|
+
status,
|
|
103
|
+
message: `Not a git repository (${status.reason.trim()}). Revise requires git for its post-flight rollback safety net. Initialize git, or re-run with --allow-dirty to opt out of the safety net.`,
|
|
104
|
+
};
|
|
105
|
+
case 'git-missing':
|
|
106
|
+
if (options.allowDirty) {
|
|
107
|
+
return {
|
|
108
|
+
ok: true,
|
|
109
|
+
status,
|
|
110
|
+
message: `git CLI not found; running with --allow-dirty. Post-flight rollback is disabled.`,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
ok: false,
|
|
115
|
+
status,
|
|
116
|
+
message: `git CLI not found on PATH. Revise requires git for its post-flight rollback safety net. Install git, or re-run with --allow-dirty to opt out.`,
|
|
117
|
+
};
|
|
118
|
+
default: {
|
|
119
|
+
const _exhaustive = status;
|
|
120
|
+
throw new Error(`unhandled GitTreeStatus: ${JSON.stringify(_exhaustive)}`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Restore a set of paths from HEAD — the primitive FEAT-013's post-flight
|
|
126
|
+
* rollback invokes when graph integrity breaks after writes. Paths are
|
|
127
|
+
* relative to `projectDir`. Empty list is a no-op.
|
|
128
|
+
*/
|
|
129
|
+
export async function checkoutPaths(projectDir, relativePaths) {
|
|
130
|
+
if (relativePaths.length === 0)
|
|
131
|
+
return;
|
|
132
|
+
await execFileAsync('git', ['checkout', '--', ...relativePaths], {
|
|
133
|
+
cwd: projectDir,
|
|
134
|
+
maxBuffer: GIT_MAX_BUFFER,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=git-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-service.js","sourceRoot":"","sources":["../../src/services/git-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read-only artifact-graph integrity check for `planr revise` post-flight
|
|
3
|
+
* (EPIC-003, FEAT-013 §3.0).
|
|
4
|
+
*
|
|
5
|
+
* Detects broken parent/child links after a revise run so FEAT-013 §4.0 can
|
|
6
|
+
* trigger automatic rollback if the writes left the tree inconsistent. This
|
|
7
|
+
* is deliberately narrower than `planr sync`: it does not fix anything, does
|
|
8
|
+
* not write to the logger, and only looks at the relationships revise might
|
|
9
|
+
* have perturbed (parent-id frontmatter fields on features, stories, tasks).
|
|
10
|
+
*
|
|
11
|
+
* Why a separate module: keeps revise decoupled from the `sync` command's
|
|
12
|
+
* repair logic, which has different invariants (fixes links, prompts the
|
|
13
|
+
* user, etc.). The check here is a pure data function.
|
|
14
|
+
*/
|
|
15
|
+
import type { ArtifactType, OpenPlanrConfig } from '../models/types.js';
|
|
16
|
+
export interface GraphIntegrityIssue {
|
|
17
|
+
childId: string;
|
|
18
|
+
childType: ArtifactType;
|
|
19
|
+
childPath: string;
|
|
20
|
+
parentField: 'epicId' | 'featureId' | 'storyId';
|
|
21
|
+
parentId: string;
|
|
22
|
+
reason: 'missing-parent' | 'parent-type-mismatch';
|
|
23
|
+
}
|
|
24
|
+
export interface GraphIntegrityReport {
|
|
25
|
+
ok: boolean;
|
|
26
|
+
issues: GraphIntegrityIssue[];
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Walk every feature/story/task and verify its parent-id frontmatter
|
|
30
|
+
* resolves to an existing parent artifact of the correct type. Missing
|
|
31
|
+
* parent-id fields are tolerated (some tasks legitimately attach at
|
|
32
|
+
* feature level, for example) — only *broken* non-empty references are
|
|
33
|
+
* reported.
|
|
34
|
+
*/
|
|
35
|
+
export declare function checkGraphIntegrity(projectDir: string, config: OpenPlanrConfig): Promise<GraphIntegrityReport>;
|
|
36
|
+
//# sourceMappingURL=graph-integrity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph-integrity.d.ts","sourceRoot":"","sources":["../../src/services/graph-integrity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAGxE,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,YAAY,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,QAAQ,GAAG,WAAW,GAAG,SAAS,CAAC;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,gBAAgB,GAAG,sBAAsB,CAAC;CACnD;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,mBAAmB,EAAE,CAAC;CAC/B;AAcD;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,eAAe,GACtB,OAAO,CAAC,oBAAoB,CAAC,CA0B/B"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read-only artifact-graph integrity check for `planr revise` post-flight
|
|
3
|
+
* (EPIC-003, FEAT-013 §3.0).
|
|
4
|
+
*
|
|
5
|
+
* Detects broken parent/child links after a revise run so FEAT-013 §4.0 can
|
|
6
|
+
* trigger automatic rollback if the writes left the tree inconsistent. This
|
|
7
|
+
* is deliberately narrower than `planr sync`: it does not fix anything, does
|
|
8
|
+
* not write to the logger, and only looks at the relationships revise might
|
|
9
|
+
* have perturbed (parent-id frontmatter fields on features, stories, tasks).
|
|
10
|
+
*
|
|
11
|
+
* Why a separate module: keeps revise decoupled from the `sync` command's
|
|
12
|
+
* repair logic, which has different invariants (fixes links, prompts the
|
|
13
|
+
* user, etc.). The check here is a pure data function.
|
|
14
|
+
*/
|
|
15
|
+
import { listArtifacts, readArtifact } from './artifact-service.js';
|
|
16
|
+
const CHECKS = [
|
|
17
|
+
{ childType: 'feature', parentField: 'epicId', parentType: 'epic' },
|
|
18
|
+
{ childType: 'story', parentField: 'featureId', parentType: 'feature' },
|
|
19
|
+
{ childType: 'task', parentField: 'storyId', parentType: 'story' },
|
|
20
|
+
];
|
|
21
|
+
/**
|
|
22
|
+
* Walk every feature/story/task and verify its parent-id frontmatter
|
|
23
|
+
* resolves to an existing parent artifact of the correct type. Missing
|
|
24
|
+
* parent-id fields are tolerated (some tasks legitimately attach at
|
|
25
|
+
* feature level, for example) — only *broken* non-empty references are
|
|
26
|
+
* reported.
|
|
27
|
+
*/
|
|
28
|
+
export async function checkGraphIntegrity(projectDir, config) {
|
|
29
|
+
const issues = [];
|
|
30
|
+
for (const spec of CHECKS) {
|
|
31
|
+
const children = await listArtifacts(projectDir, config, spec.childType);
|
|
32
|
+
for (const childRow of children) {
|
|
33
|
+
const child = await readArtifact(projectDir, config, spec.childType, childRow.id);
|
|
34
|
+
if (!child)
|
|
35
|
+
continue;
|
|
36
|
+
const parentId = child.data[spec.parentField];
|
|
37
|
+
if (!parentId)
|
|
38
|
+
continue; // optional ref — not a broken link
|
|
39
|
+
const parent = await readArtifact(projectDir, config, spec.parentType, parentId);
|
|
40
|
+
if (!parent) {
|
|
41
|
+
issues.push({
|
|
42
|
+
childId: childRow.id,
|
|
43
|
+
childType: spec.childType,
|
|
44
|
+
childPath: child.filePath,
|
|
45
|
+
parentField: spec.parentField,
|
|
46
|
+
parentId,
|
|
47
|
+
reason: 'missing-parent',
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return { ok: issues.length === 0, issues };
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=graph-integrity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph-integrity.js","sourceRoot":"","sources":["../../src/services/graph-integrity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAsBpE,MAAM,MAAM,GAAgB;IAC1B,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE;IACnE,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE;IACvE,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE;CACnE,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,UAAkB,EAClB,MAAuB;IAEvB,MAAM,MAAM,GAA0B,EAAE,CAAC;IAEzC,KAAK,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;QAC1B,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QACzE,KAAK,MAAM,QAAQ,IAAI,QAAQ,EAAE,CAAC;YAChC,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC;YAClF,IAAI,CAAC,KAAK;gBAAE,SAAS;YACrB,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAuB,CAAC;YACpE,IAAI,CAAC,QAAQ;gBAAE,SAAS,CAAC,mCAAmC;YAE5D,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;YACjF,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,MAAM,CAAC,IAAI,CAAC;oBACV,OAAO,EAAE,QAAQ,CAAC,EAAE;oBACpB,SAAS,EAAE,IAAI,CAAC,SAAS;oBACzB,SAAS,EAAE,KAAK,CAAC,QAAQ;oBACzB,WAAW,EAAE,IAAI,CAAC,WAAW;oBAC7B,QAAQ;oBACR,MAAM,EAAE,gBAAgB;iBACzB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;AAC7C,CAAC"}
|
|
@@ -19,4 +19,22 @@ export declare function promptCheckbox<T extends string>(message: string, choice
|
|
|
19
19
|
}>): Promise<T[]>;
|
|
20
20
|
/** Prompt the user for comma-separated text values, returned as a trimmed array. */
|
|
21
21
|
export declare function promptMultiText(message: string, hint?: string): Promise<string[]>;
|
|
22
|
+
/** One action the user can take at the diff-preview prompt for a proposed revise. */
|
|
23
|
+
export type ReviseConfirmAction = 'apply' | 'skip' | 'edit-rationale' | 'diff-again' | 'quit';
|
|
24
|
+
/**
|
|
25
|
+
* Prompt the user for the per-artifact revise confirmation menu. In
|
|
26
|
+
* non-interactive mode, returns `apply` by default (caller should only
|
|
27
|
+
* enter this path after the typed-YES gate in `confirmBulkRevise`).
|
|
28
|
+
*/
|
|
29
|
+
export declare function promptReviseConfirm(artifactId: string): Promise<ReviseConfirmAction>;
|
|
30
|
+
/**
|
|
31
|
+
* Typed-YES confirmation gate for `--yes` bulk-apply runs.
|
|
32
|
+
*
|
|
33
|
+
* In an interactive TTY, prints the provided summary and blocks on the user
|
|
34
|
+
* typing "YES" (case-sensitive) to proceed. In non-TTY environments
|
|
35
|
+
* (piped stdout, CI), returns `true` unconditionally — the `--yes` flag
|
|
36
|
+
* alone is the contract with the pipeline, and PR review is the upstream
|
|
37
|
+
* human gate. Returns `false` if the user types anything other than "YES".
|
|
38
|
+
*/
|
|
39
|
+
export declare function confirmBulkRevise(summary: string): Promise<boolean>;
|
|
22
40
|
//# sourceMappingURL=prompt-service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompt-service.d.ts","sourceRoot":"","sources":["../../src/services/prompt-service.ts"],"names":[],"mappings":"AAIA,2GAA2G;AAC3G,wBAAsB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CASxF;AAED,wDAAwD;AACxD,wBAAsB,YAAY,CAAC,CAAC,SAAS,MAAM,EACjD,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,CAAC,CAAA;CAAE,CAAC,EAC1C,YAAY,CAAC,EAAE,CAAC,GACf,OAAO,CAAC,CAAC,CAAC,CAOZ;AAED,iDAAiD;AACjD,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,UAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAM1F;AAED,gEAAgE;AAChE,wBAAsB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAW1F;AAED,kEAAkE;AAClE,wBAAsB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAMnE;AAED,uEAAuE;AACvE,wBAAsB,cAAc,CAAC,CAAC,SAAS,MAAM,EACnD,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,GAC5D,OAAO,CAAC,CAAC,EAAE,CAAC,CAOd;AAED,oFAAoF;AACpF,wBAAsB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAavF"}
|
|
1
|
+
{"version":3,"file":"prompt-service.d.ts","sourceRoot":"","sources":["../../src/services/prompt-service.ts"],"names":[],"mappings":"AAIA,2GAA2G;AAC3G,wBAAsB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CASxF;AAED,wDAAwD;AACxD,wBAAsB,YAAY,CAAC,CAAC,SAAS,MAAM,EACjD,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,CAAC,CAAA;CAAE,CAAC,EAC1C,YAAY,CAAC,EAAE,CAAC,GACf,OAAO,CAAC,CAAC,CAAC,CAOZ;AAED,iDAAiD;AACjD,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,UAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAM1F;AAED,gEAAgE;AAChE,wBAAsB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAW1F;AAED,kEAAkE;AAClE,wBAAsB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAMnE;AAED,uEAAuE;AACvE,wBAAsB,cAAc,CAAC,CAAC,SAAS,MAAM,EACnD,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,GAC5D,OAAO,CAAC,CAAC,EAAE,CAAC,CAOd;AAED,oFAAoF;AACpF,wBAAsB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAavF;AAMD,qFAAqF;AACrF,MAAM,MAAM,mBAAmB,GAAG,OAAO,GAAG,MAAM,GAAG,gBAAgB,GAAG,YAAY,GAAG,MAAM,CAAC;AAU9F;;;;GAIG;AACH,wBAAsB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAU1F;AAED;;;;;;;;GAQG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAczE"}
|
|
@@ -70,4 +70,51 @@ export async function promptMultiText(message, hint) {
|
|
|
70
70
|
.map((s) => s.trim())
|
|
71
71
|
.filter(Boolean);
|
|
72
72
|
}
|
|
73
|
+
const REVISE_CONFIRM_CHOICES = [
|
|
74
|
+
{ name: '[a] Apply — write this revision to disk', value: 'apply' },
|
|
75
|
+
{ name: '[s] Skip — do not write; cascade continues', value: 'skip' },
|
|
76
|
+
{ name: '[e] Edit rationale — record a human reason for this decision', value: 'edit-rationale' },
|
|
77
|
+
{ name: '[d] Diff again — re-print the diff', value: 'diff-again' },
|
|
78
|
+
{ name: '[q] Quit — stop cascade; already-applied artifacts remain applied', value: 'quit' },
|
|
79
|
+
];
|
|
80
|
+
/**
|
|
81
|
+
* Prompt the user for the per-artifact revise confirmation menu. In
|
|
82
|
+
* non-interactive mode, returns `apply` by default (caller should only
|
|
83
|
+
* enter this path after the typed-YES gate in `confirmBulkRevise`).
|
|
84
|
+
*/
|
|
85
|
+
export async function promptReviseConfirm(artifactId) {
|
|
86
|
+
if (isNonInteractive()) {
|
|
87
|
+
logger.dim(` [auto] Revise ${artifactId} → apply`);
|
|
88
|
+
return 'apply';
|
|
89
|
+
}
|
|
90
|
+
return select({
|
|
91
|
+
message: `Revise ${artifactId}:`,
|
|
92
|
+
choices: REVISE_CONFIRM_CHOICES,
|
|
93
|
+
default: 'apply',
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Typed-YES confirmation gate for `--yes` bulk-apply runs.
|
|
98
|
+
*
|
|
99
|
+
* In an interactive TTY, prints the provided summary and blocks on the user
|
|
100
|
+
* typing "YES" (case-sensitive) to proceed. In non-TTY environments
|
|
101
|
+
* (piped stdout, CI), returns `true` unconditionally — the `--yes` flag
|
|
102
|
+
* alone is the contract with the pipeline, and PR review is the upstream
|
|
103
|
+
* human gate. Returns `false` if the user types anything other than "YES".
|
|
104
|
+
*/
|
|
105
|
+
export async function confirmBulkRevise(summary) {
|
|
106
|
+
// Non-TTY: the flag is sufficient. Humans can't type at pipelines.
|
|
107
|
+
if (!process.stdout.isTTY) {
|
|
108
|
+
logger.dim('Non-interactive environment detected — --yes flag accepted without typed-YES.');
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
if (isNonInteractive()) {
|
|
112
|
+
// Explicit --no-interactive / -y also skips the typed-YES.
|
|
113
|
+
logger.dim('Non-interactive mode — --yes flag accepted without typed-YES.');
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
logger.info(summary);
|
|
117
|
+
const typed = await input({ message: 'Type YES to continue:' });
|
|
118
|
+
return typed === 'YES';
|
|
119
|
+
}
|
|
73
120
|
//# sourceMappingURL=prompt-service.js.map
|
|
@@ -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,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content-hash run cache for `planr revise` (EPIC-003, FEAT-014 §2.0).
|
|
3
|
+
*
|
|
4
|
+
* Between runs, we hash each artifact's raw content (+ the codebase-digest
|
|
5
|
+
* input, when present) and skip artifacts whose hash matches the last
|
|
6
|
+
* successful revise of that artifact with the same codebase state. Keeps
|
|
7
|
+
* `--all` cheap to re-run on an untouched repo (a common check-before-PR
|
|
8
|
+
* workflow) without sacrificing correctness: any edit to the artifact or
|
|
9
|
+
* the codebase invalidates the cache entry automatically.
|
|
10
|
+
*
|
|
11
|
+
* Persisted at `.planr/reports/.revise-cache.json`. JSON was chosen over
|
|
12
|
+
* a line-oriented format because the cache is small (one entry per
|
|
13
|
+
* artifact) and atomic updates via atomicWriteFile are simpler with JSON.
|
|
14
|
+
*
|
|
15
|
+
* Cache semantics are best-effort: if the cache file is missing or
|
|
16
|
+
* malformed, reads return empty (never throw). Writes are fire-and-forget.
|
|
17
|
+
*/
|
|
18
|
+
export interface ReviseCacheEntry {
|
|
19
|
+
artifactHash: string;
|
|
20
|
+
/** Digest over codebase-context-relevant state (folder tree, architecture files) — optional. */
|
|
21
|
+
codebaseHash?: string;
|
|
22
|
+
lastOutcome: 'skipped-by-agent' | 'applied' | 'would-apply' | 'flagged';
|
|
23
|
+
lastRunAt: string;
|
|
24
|
+
}
|
|
25
|
+
export interface ReviseCache {
|
|
26
|
+
entries: Record<string, ReviseCacheEntry>;
|
|
27
|
+
}
|
|
28
|
+
export declare function defaultCachePath(projectDir: string): string;
|
|
29
|
+
export declare function loadCache(projectDir: string): ReviseCache;
|
|
30
|
+
export declare function saveCache(projectDir: string, cache: ReviseCache): Promise<void>;
|
|
31
|
+
/** SHA-256 of the artifact raw content (body + frontmatter) used as cache key. */
|
|
32
|
+
export declare function hashArtifactContent(raw: string): string;
|
|
33
|
+
/** Optional SHA-256 over the codebase context string, so code changes invalidate cache. */
|
|
34
|
+
export declare function hashCodebaseContext(formatted?: string): string | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* Returns true when the given artifact + codebase hash matches the cache
|
|
37
|
+
* entry from a prior successful revise — caller may skip the AI call.
|
|
38
|
+
* A mismatch on either dimension invalidates the entry.
|
|
39
|
+
*/
|
|
40
|
+
export declare function shouldSkipArtifact(cache: ReviseCache, artifactId: string, artifactHash: string, codebaseHash: string | undefined): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Record an outcome in the cache. Returns a new cache object (pure) so
|
|
43
|
+
* callers can decide when to flush.
|
|
44
|
+
*/
|
|
45
|
+
export declare function recordOutcome(cache: ReviseCache, artifactId: string, artifactHash: string, codebaseHash: string | undefined, outcome: ReviseCacheEntry['lastOutcome']): ReviseCache;
|
|
46
|
+
//# sourceMappingURL=revise-cache-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"revise-cache-service.d.ts","sourceRoot":"","sources":["../../src/services/revise-cache-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAOH,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,gGAAgG;IAChG,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,kBAAkB,GAAG,SAAS,GAAG,aAAa,GAAG,SAAS,CAAC;IACxE,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;CAC3C;AAID,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,WAAW,CAazD;AAED,wBAAsB,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAErF;AAED,kFAAkF;AAClF,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED,2FAA2F;AAC3F,wBAAgB,mBAAmB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAG1E;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,WAAW,EAClB,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,GAAG,SAAS,GAC/B,OAAO,CAOT;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,WAAW,EAClB,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,OAAO,EAAE,gBAAgB,CAAC,aAAa,CAAC,GACvC,WAAW,CAYb"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content-hash run cache for `planr revise` (EPIC-003, FEAT-014 §2.0).
|
|
3
|
+
*
|
|
4
|
+
* Between runs, we hash each artifact's raw content (+ the codebase-digest
|
|
5
|
+
* input, when present) and skip artifacts whose hash matches the last
|
|
6
|
+
* successful revise of that artifact with the same codebase state. Keeps
|
|
7
|
+
* `--all` cheap to re-run on an untouched repo (a common check-before-PR
|
|
8
|
+
* workflow) without sacrificing correctness: any edit to the artifact or
|
|
9
|
+
* the codebase invalidates the cache entry automatically.
|
|
10
|
+
*
|
|
11
|
+
* Persisted at `.planr/reports/.revise-cache.json`. JSON was chosen over
|
|
12
|
+
* a line-oriented format because the cache is small (one entry per
|
|
13
|
+
* artifact) and atomic updates via atomicWriteFile are simpler with JSON.
|
|
14
|
+
*
|
|
15
|
+
* Cache semantics are best-effort: if the cache file is missing or
|
|
16
|
+
* malformed, reads return empty (never throw). Writes are fire-and-forget.
|
|
17
|
+
*/
|
|
18
|
+
import { createHash } from 'node:crypto';
|
|
19
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
20
|
+
import path from 'node:path';
|
|
21
|
+
import { atomicWriteFile } from './atomic-write-service.js';
|
|
22
|
+
const EMPTY = { entries: {} };
|
|
23
|
+
export function defaultCachePath(projectDir) {
|
|
24
|
+
return path.join(projectDir, '.planr', 'reports', '.revise-cache.json');
|
|
25
|
+
}
|
|
26
|
+
export function loadCache(projectDir) {
|
|
27
|
+
const p = defaultCachePath(projectDir);
|
|
28
|
+
if (!existsSync(p))
|
|
29
|
+
return { entries: {} };
|
|
30
|
+
try {
|
|
31
|
+
const raw = readFileSync(p, 'utf-8');
|
|
32
|
+
const parsed = JSON.parse(raw);
|
|
33
|
+
if (parsed && typeof parsed === 'object' && parsed.entries) {
|
|
34
|
+
return { entries: parsed.entries };
|
|
35
|
+
}
|
|
36
|
+
return EMPTY;
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return EMPTY;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
export async function saveCache(projectDir, cache) {
|
|
43
|
+
await atomicWriteFile(defaultCachePath(projectDir), JSON.stringify(cache, null, 2));
|
|
44
|
+
}
|
|
45
|
+
/** SHA-256 of the artifact raw content (body + frontmatter) used as cache key. */
|
|
46
|
+
export function hashArtifactContent(raw) {
|
|
47
|
+
return createHash('sha256').update(raw).digest('hex');
|
|
48
|
+
}
|
|
49
|
+
/** Optional SHA-256 over the codebase context string, so code changes invalidate cache. */
|
|
50
|
+
export function hashCodebaseContext(formatted) {
|
|
51
|
+
if (!formatted)
|
|
52
|
+
return undefined;
|
|
53
|
+
return createHash('sha256').update(formatted).digest('hex');
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Returns true when the given artifact + codebase hash matches the cache
|
|
57
|
+
* entry from a prior successful revise — caller may skip the AI call.
|
|
58
|
+
* A mismatch on either dimension invalidates the entry.
|
|
59
|
+
*/
|
|
60
|
+
export function shouldSkipArtifact(cache, artifactId, artifactHash, codebaseHash) {
|
|
61
|
+
const entry = cache.entries[artifactId];
|
|
62
|
+
if (!entry)
|
|
63
|
+
return false;
|
|
64
|
+
if (entry.artifactHash !== artifactHash)
|
|
65
|
+
return false;
|
|
66
|
+
if (entry.codebaseHash !== codebaseHash)
|
|
67
|
+
return false;
|
|
68
|
+
// Only cache-skip when the prior outcome indicated "nothing to do".
|
|
69
|
+
return entry.lastOutcome === 'skipped-by-agent';
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Record an outcome in the cache. Returns a new cache object (pure) so
|
|
73
|
+
* callers can decide when to flush.
|
|
74
|
+
*/
|
|
75
|
+
export function recordOutcome(cache, artifactId, artifactHash, codebaseHash, outcome) {
|
|
76
|
+
return {
|
|
77
|
+
entries: {
|
|
78
|
+
...cache.entries,
|
|
79
|
+
[artifactId]: {
|
|
80
|
+
artifactHash,
|
|
81
|
+
codebaseHash,
|
|
82
|
+
lastOutcome: outcome,
|
|
83
|
+
lastRunAt: new Date().toISOString(),
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=revise-cache-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"revise-cache-service.js","sourceRoot":"","sources":["../../src/services/revise-cache-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `planr revise` — core service (EPIC-003, FEAT-010 + FEAT-011).
|
|
3
|
+
*
|
|
4
|
+
* Exposes composable primitives; the CLI and future cascade service
|
|
5
|
+
* orchestrate them. Phase 1 (FEAT-010) ships `reviseArtifact` for dry-run
|
|
6
|
+
* decision generation; Phase 2 (FEAT-011) adds `applyDecision` for the
|
|
7
|
+
* write path and exposes the verifier context so callers can run
|
|
8
|
+
* `verifyDecision` against the same inputs the agent saw.
|
|
9
|
+
*/
|
|
10
|
+
import { type RevisePromptArtifact, type ReviseWritableScope } from '../ai/prompts/prompt-builder.js';
|
|
11
|
+
import { type AIProvider, type AIUsage } from '../ai/types.js';
|
|
12
|
+
import type { ArtifactType, OpenPlanrConfig, ReviseAuditEntry, ReviseDecision } from '../models/types.js';
|
|
13
|
+
import type { AuditLogWriter } from './audit-log-service.js';
|
|
14
|
+
import type { EvidenceVerifierContext } from './evidence-verifier.js';
|
|
15
|
+
export interface ReviseArtifactOptions {
|
|
16
|
+
/** Must be `true` in Phase 1; reserved for future write path (FEAT-011). */
|
|
17
|
+
dryRun: true;
|
|
18
|
+
/** Which parts of the artifact the agent may modify. Default: 'all'. */
|
|
19
|
+
writableScope?: ReviseWritableScope;
|
|
20
|
+
/** Skip codebase context assembly (fast mode). Default: include code. */
|
|
21
|
+
noCodeContext?: boolean;
|
|
22
|
+
/** Skip immediate-sibling context gathering (fast mode / first-pass). Default: include. */
|
|
23
|
+
noSiblingContext?: boolean;
|
|
24
|
+
/** Maximum number of sibling artifacts to inject (budget guard). Default: 8. */
|
|
25
|
+
maxSiblings?: number;
|
|
26
|
+
}
|
|
27
|
+
export interface ReviseArtifactContextStats {
|
|
28
|
+
parentsLoaded: number;
|
|
29
|
+
siblingsLoaded: number;
|
|
30
|
+
codebaseContextIncluded: boolean;
|
|
31
|
+
sourcesLoaded: number;
|
|
32
|
+
}
|
|
33
|
+
export interface ReviseArtifactResult {
|
|
34
|
+
decision: ReviseDecision;
|
|
35
|
+
usage: AIUsage;
|
|
36
|
+
contextStats: ReviseArtifactContextStats;
|
|
37
|
+
/** Filesystem path the decision's revisedMarkdown would be written to. */
|
|
38
|
+
artifactPath: string;
|
|
39
|
+
/** Pre-revise raw content, used for diff rendering and auditing. */
|
|
40
|
+
originalContent: string;
|
|
41
|
+
/** Context the caller should pass to `verifyDecision`. */
|
|
42
|
+
verifierContext: EvidenceVerifierContext;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Error thrown when an artifact id cannot be resolved to an artifact type or
|
|
46
|
+
* the artifact file does not exist on disk.
|
|
47
|
+
*/
|
|
48
|
+
export declare class ReviseArtifactNotFoundError extends Error {
|
|
49
|
+
readonly artifactId: string;
|
|
50
|
+
constructor(artifactId: string, message: string);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Revise a single artifact — Phase 1 dry-run.
|
|
54
|
+
*
|
|
55
|
+
* Does NOT write any files. The returned decision is the agent output after
|
|
56
|
+
* schema validation; evidence verification, diff preview, and write are all
|
|
57
|
+
* Phase 2 responsibilities (FEAT-011). Cascade, siblings, and declared
|
|
58
|
+
* sources are Phase 3 (FEAT-012) and onwards.
|
|
59
|
+
*/
|
|
60
|
+
export declare function reviseArtifact(projectDir: string, config: OpenPlanrConfig, provider: AIProvider, artifactId: string, options: ReviseArtifactOptions): Promise<ReviseArtifactResult>;
|
|
61
|
+
export interface ApplyDecisionOptions {
|
|
62
|
+
artifactPath: string;
|
|
63
|
+
originalContent: string;
|
|
64
|
+
decision: ReviseDecision;
|
|
65
|
+
/**
|
|
66
|
+
* Directory where sidecar backups are written. Typically
|
|
67
|
+
* `.planr/reports/revise-<scope>-<date>/backup/` — set by the CLI.
|
|
68
|
+
*/
|
|
69
|
+
backupDir: string;
|
|
70
|
+
/** Audit writer that will persist an entry describing the outcome. */
|
|
71
|
+
audit: AuditLogWriter;
|
|
72
|
+
/** When true, produces an audit entry but does not write the artifact. */
|
|
73
|
+
dryRun: boolean;
|
|
74
|
+
/** Cascade level tag for audit log grouping; omit for single-artifact runs. */
|
|
75
|
+
cascadeLevel?: ReviseAuditEntry['cascadeLevel'];
|
|
76
|
+
}
|
|
77
|
+
export interface ApplyDecisionResult {
|
|
78
|
+
outcome: ReviseAuditEntry['outcome'];
|
|
79
|
+
wrote: boolean;
|
|
80
|
+
diff: string;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Apply a (verified) decision: write the artifact atomically when
|
|
84
|
+
* `action === 'revise'` and `dryRun` is false, emit an audit entry
|
|
85
|
+
* describing the outcome either way.
|
|
86
|
+
*
|
|
87
|
+
* Caller is expected to have already run `verifyDecision` — `applyDecision`
|
|
88
|
+
* trusts that whatever decision arrives is allowed to be written.
|
|
89
|
+
*/
|
|
90
|
+
export declare function applyDecision(options: ApplyDecisionOptions): Promise<ApplyDecisionResult>;
|
|
91
|
+
/**
|
|
92
|
+
* Load immediate-sibling artifacts (same artifact type, same parent) as
|
|
93
|
+
* prompt entries. Lazy-reads each sibling's body only if it's going to be
|
|
94
|
+
* included — the listing check is cheap, the reads are budgeted by
|
|
95
|
+
* `maxSiblings` (default 8) so the prompt stays within token budget even on
|
|
96
|
+
* epics with many features.
|
|
97
|
+
*
|
|
98
|
+
* For epic scope, there are no siblings (epics live at the top). For types
|
|
99
|
+
* without a parent-id relationship (quick, backlog, etc.), returns empty.
|
|
100
|
+
*/
|
|
101
|
+
export declare function loadSiblingPromptArtifacts(projectDir: string, config: OpenPlanrConfig, type: ArtifactType, id: string, maxSiblings: number): Promise<RevisePromptArtifact[]>;
|
|
102
|
+
/**
|
|
103
|
+
* Resolve the parent chain for an artifact and return it as the ordered
|
|
104
|
+
* `RevisePromptArtifact[]` the prompt builder expects (epic → feature →
|
|
105
|
+
* story). Empty array for top-level artifacts (epic scope).
|
|
106
|
+
*/
|
|
107
|
+
export declare function loadParentPromptArtifacts(projectDir: string, config: OpenPlanrConfig, type: ArtifactType, id: string): Promise<RevisePromptArtifact[]>;
|
|
108
|
+
//# sourceMappingURL=revise-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"revise-service.d.ts","sourceRoot":"","sources":["../../src/services/revise-service.ts"],"names":[],"mappings":"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"}
|