@agent-plan/core 0.2.28 → 0.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.
- package/dist/accepted-decision-guard.d.ts +94 -0
- package/dist/accepted-decision-guard.d.ts.map +1 -0
- package/dist/accepted-decision-guard.js +110 -0
- package/dist/checklist.d.ts +28 -0
- package/dist/checklist.d.ts.map +1 -1
- package/dist/checklist.js +59 -0
- package/dist/feature-delete.d.ts +62 -0
- package/dist/feature-delete.d.ts.map +1 -0
- package/dist/feature-delete.js +49 -0
- package/dist/guard-decision.d.ts +118 -0
- package/dist/guard-decision.d.ts.map +1 -0
- package/dist/guard-decision.js +203 -0
- package/dist/handoff-context.d.ts +130 -1
- package/dist/handoff-context.d.ts.map +1 -1
- package/dist/handoff-context.js +167 -9
- package/dist/handoff-reply.d.ts +108 -0
- package/dist/handoff-reply.d.ts.map +1 -0
- package/dist/handoff-reply.js +279 -0
- package/dist/index.d.ts +15 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -1
- package/dist/mutation-reply.d.ts +105 -0
- package/dist/mutation-reply.d.ts.map +1 -0
- package/dist/mutation-reply.js +203 -0
- package/dist/naming.d.ts +1 -1
- package/dist/naming.d.ts.map +1 -1
- package/dist/naming.js +1 -1
- package/dist/pagination.d.ts +19 -0
- package/dist/pagination.d.ts.map +1 -0
- package/dist/pagination.js +15 -0
- package/dist/payload-fallback.js +1 -1
- package/dist/plan-store.d.ts +141 -8
- package/dist/plan-store.d.ts.map +1 -1
- package/dist/plan-store.js +459 -87
- package/dist/project-context-migration.d.ts +5 -0
- package/dist/project-context-migration.d.ts.map +1 -1
- package/dist/project-context-migration.js +13 -0
- package/dist/project-context.d.ts +395 -0
- package/dist/project-context.d.ts.map +1 -0
- package/dist/project-context.js +295 -0
- package/dist/recap.d.ts.map +1 -1
- package/dist/recap.js +27 -0
- package/dist/recommend-reply.d.ts +51 -0
- package/dist/recommend-reply.d.ts.map +1 -0
- package/dist/recommend-reply.js +84 -0
- package/dist/refs.d.ts +16 -0
- package/dist/refs.d.ts.map +1 -1
- package/dist/refs.js +38 -0
- package/dist/renderer.d.ts.map +1 -1
- package/dist/schema.d.ts +7 -2
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +8 -3
- package/dist/stranded-phase.d.ts +73 -0
- package/dist/stranded-phase.d.ts.map +1 -0
- package/dist/stranded-phase.js +93 -0
- package/dist/task-completion-gate.d.ts +84 -0
- package/dist/task-completion-gate.d.ts.map +1 -0
- package/dist/task-completion-gate.js +72 -0
- package/dist/task-context.d.ts +1 -0
- package/dist/task-context.d.ts.map +1 -1
- package/dist/task-context.js +31 -13
- package/dist/task-lifecycle.d.ts +12 -0
- package/dist/task-lifecycle.d.ts.map +1 -0
- package/dist/task-lifecycle.js +23 -0
- package/dist/task-order-context.d.ts +72 -0
- package/dist/task-order-context.d.ts.map +1 -0
- package/dist/task-order-context.js +82 -0
- package/dist/task-selection.d.ts.map +1 -1
- package/dist/task-selection.js +14 -12
- package/dist/task-start-outcome.d.ts +26 -0
- package/dist/task-start-outcome.d.ts.map +1 -1
- package/dist/task-start-outcome.js +23 -0
- package/dist/text-bounds.d.ts +32 -0
- package/dist/text-bounds.d.ts.map +1 -0
- package/dist/text-bounds.js +43 -0
- package/dist/write-coordination.d.ts +2 -2
- package/dist/write-coordination.js +2 -2
- package/package.json +1 -1
- package/planner-skill.md +30 -12
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { realpathSync } from "node:fs";
|
|
2
|
+
import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
3
|
+
const GUARDED_FILE_TOOLS = new Set(["Edit", "Write"]);
|
|
4
|
+
/** Strip fd-duplication idioms (`2>&1`, `>&2`, `1>&2`) before segmenting or
|
|
5
|
+
* matching — they duplicate a stream, not a file, are extremely common in
|
|
6
|
+
* otherwise read-only commands, and their bare `&` would otherwise be
|
|
7
|
+
* misread as a command separator by {@link bashSegments}. */
|
|
8
|
+
function stripFdDuplication(command) {
|
|
9
|
+
return command.replace(/\d*>&\d+/g, " ");
|
|
10
|
+
}
|
|
11
|
+
/** Split a Bash command line into pipe/list segments so write-detection on
|
|
12
|
+
* one segment (e.g. `sed -i` on the left of a pipe) doesn't get confused by
|
|
13
|
+
* an unrelated flag on the other side (e.g. `grep -i` on the right). Best
|
|
14
|
+
* effort only — quoting and nested subshells are not fully parsed. Callers
|
|
15
|
+
* must strip fd-duplication first, or a bare `2>&1` splits on its `&`. */
|
|
16
|
+
function bashSegments(command) {
|
|
17
|
+
return command
|
|
18
|
+
.split(/(?:&&|\|\||[;&|\n])+/)
|
|
19
|
+
.map((segment) => segment.trim())
|
|
20
|
+
.filter(Boolean);
|
|
21
|
+
}
|
|
22
|
+
const GIT_TREE_WRITE_RE = /\bgit\s+(?:checkout|apply|restore|stash\s+pop|reset\s+--hard)\b/;
|
|
23
|
+
const IN_PLACE_EDITOR_RE = /\b(sed|perl)\b/;
|
|
24
|
+
const IN_PLACE_FLAG_RE = /(^|\s)-\S*i(\s|$)/;
|
|
25
|
+
function isWriteShapedBashSegment(segment) {
|
|
26
|
+
if (/>{1,2}/.test(segment))
|
|
27
|
+
return true;
|
|
28
|
+
if (/\btee\b/.test(segment))
|
|
29
|
+
return true;
|
|
30
|
+
if (/\b(cp|mv)\b/.test(segment))
|
|
31
|
+
return true;
|
|
32
|
+
if (/\brm\b/.test(segment))
|
|
33
|
+
return true;
|
|
34
|
+
if (GIT_TREE_WRITE_RE.test(segment))
|
|
35
|
+
return true;
|
|
36
|
+
if (IN_PLACE_EDITOR_RE.test(segment) && IN_PLACE_FLAG_RE.test(segment))
|
|
37
|
+
return true;
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Whether a Bash command line contains a write-shaped operation: output
|
|
42
|
+
* redirection, `tee`, in-place `sed`/`perl`, a file-creating `cp`/`mv`,
|
|
43
|
+
* `rm`, or a `git` operation that rewrites tracked files. Deliberately
|
|
44
|
+
* over-inclusive: `git`, build/test runners, `ls`, `cat`, `grep`, `find`
|
|
45
|
+
* and friends must stay unmatched, but when in doubt this returns true — the
|
|
46
|
+
* cost of a false positive here is one extra prompt, not a blocked
|
|
47
|
+
* operation, so under-matching (missing a real edit) is the worse failure.
|
|
48
|
+
*/
|
|
49
|
+
export function isWriteShapedBashCommand(command) {
|
|
50
|
+
if (!command || !command.trim())
|
|
51
|
+
return false;
|
|
52
|
+
return bashSegments(stripFdDuplication(command)).some(isWriteShapedBashSegment);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Best-effort extraction of the file path(s) a write-shaped Bash segment
|
|
56
|
+
* targets, so a command that only touches `.planner/` can still be
|
|
57
|
+
* recognized and allowed. This cannot see through a heredoc whose target is
|
|
58
|
+
* computed (a variable, command substitution, etc.) rather than written
|
|
59
|
+
* literally in the command line — that case is expected to fall through to
|
|
60
|
+
* the normal in-progress/bypass checks below, not to be silently allowed.
|
|
61
|
+
*
|
|
62
|
+
* A wider gap of the same kind: a command that writes through an
|
|
63
|
+
* interpreter (`python3 - <<PY` then `open(path, "w")`, `node -e`, a script
|
|
64
|
+
* invoked by name) is opaque here — nothing in the command line looks
|
|
65
|
+
* write-shaped. P105(F005)/T431 evaluated closing this and chose not to,
|
|
66
|
+
* for reasons that also rule out revisiting it the same way later:
|
|
67
|
+
* - Parsing the script body is unbounded (a path can be computed, read
|
|
68
|
+
* from argv, or built at runtime) and would trade an honest documented
|
|
69
|
+
* limit for false confidence.
|
|
70
|
+
* - A PostToolUse hook that notices tracked files changed while no task
|
|
71
|
+
* was in progress sounds like a fit (the guard's job is visibility, not
|
|
72
|
+
* prevention), but it collides with this project's own workflow: a
|
|
73
|
+
* task is left with its changes uncommitted for the orchestrator to
|
|
74
|
+
* review, so "no task in-progress, tracked files changed outside
|
|
75
|
+
* .planner/" is the routine state right after every task completes,
|
|
76
|
+
* not a signal of anything wrong. Telling that apart from a real
|
|
77
|
+
* interpreter write means diffing only the delta from one specific
|
|
78
|
+
* Bash call, which needs a session-scoped git-status baseline checked
|
|
79
|
+
* on every Bash invocation — read-only ones included, since which
|
|
80
|
+
* commands wrote can't be known in advance. That statefulness and
|
|
81
|
+
* per-call cost is worse than the gap it would close.
|
|
82
|
+
* The limit stands, documented rather than silently assumed away.
|
|
83
|
+
*/
|
|
84
|
+
export function extractBashWriteTargets(command) {
|
|
85
|
+
const targets = [];
|
|
86
|
+
for (const segment of bashSegments(stripFdDuplication(command))) {
|
|
87
|
+
const redirect = segment.match(/>{1,2}\s*([^\s;&|>]+)/);
|
|
88
|
+
if (redirect?.[1])
|
|
89
|
+
targets.push(redirect[1]);
|
|
90
|
+
const tee = segment.match(/\btee\b\s+(?:-\S+\s+)*([^\s;&|]+)/);
|
|
91
|
+
if (tee?.[1])
|
|
92
|
+
targets.push(tee[1]);
|
|
93
|
+
if (/\b(cp|mv)\b/.test(segment)) {
|
|
94
|
+
const tokens = segment.trim().split(/\s+/).filter((token) => !token.startsWith("-"));
|
|
95
|
+
const last = tokens[tokens.length - 1];
|
|
96
|
+
if (last && !/^(cp|mv)$/.test(last))
|
|
97
|
+
targets.push(last);
|
|
98
|
+
}
|
|
99
|
+
if (/\brm\b/.test(segment)) {
|
|
100
|
+
const tokens = segment.trim().split(/\s+/).filter((token) => !token.startsWith("-") && token !== "rm");
|
|
101
|
+
targets.push(...tokens);
|
|
102
|
+
}
|
|
103
|
+
if (IN_PLACE_EDITOR_RE.test(segment) && IN_PLACE_FLAG_RE.test(segment)) {
|
|
104
|
+
const tokens = segment.trim().split(/\s+/);
|
|
105
|
+
const last = tokens[tokens.length - 1];
|
|
106
|
+
if (last && !last.startsWith("-"))
|
|
107
|
+
targets.push(last);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return targets.filter(Boolean);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Canonicalize a path by resolving symlinks wherever the filesystem lets us,
|
|
114
|
+
* so e.g. a macOS temp dir under `/var` (itself a symlink to `/private/var`)
|
|
115
|
+
* compares equal to a path already given in its resolved form, instead of
|
|
116
|
+
* two spellings of the same directory looking like different ones. `Edit`
|
|
117
|
+
* targets an existing file, but `Write` and Bash redirects can target a path
|
|
118
|
+
* that doesn't exist yet — realpath() throws ENOENT for those, so this walks
|
|
119
|
+
* up to the nearest existing ancestor, canonicalizes that, and reattaches
|
|
120
|
+
* the missing tail. Never throws; worst case it returns `path` unchanged.
|
|
121
|
+
*/
|
|
122
|
+
function canonicalize(path) {
|
|
123
|
+
try {
|
|
124
|
+
return realpathSync(path);
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
const parent = dirname(path);
|
|
128
|
+
if (parent === path)
|
|
129
|
+
return path; // reached the filesystem root
|
|
130
|
+
return join(canonicalize(parent), basename(path));
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/** Whether `candidate` resolves to a path inside `plannerRoot` (or is it exactly). */
|
|
134
|
+
export function isPathInsidePlannerRoot(candidate, plannerRoot, cwd) {
|
|
135
|
+
const resolvedRoot = canonicalize(resolve(plannerRoot));
|
|
136
|
+
const resolvedCandidate = canonicalize(resolve(cwd, candidate));
|
|
137
|
+
const rel = relative(resolvedRoot, resolvedCandidate);
|
|
138
|
+
return rel === "" || (!rel.startsWith("..") && !isAbsolute(rel));
|
|
139
|
+
}
|
|
140
|
+
/** True only when every candidate path is inside the planner root, and there
|
|
141
|
+
* is at least one candidate — an empty/unknown path list must never count as
|
|
142
|
+
* "inside", or an unresolvable target would be silently allowed. Exported so
|
|
143
|
+
* a hook harness can use the exact same check for its cheap early-allow path
|
|
144
|
+
* without duplicating the rule. */
|
|
145
|
+
export function isEntirelyInsidePlannerRoot(paths, plannerRoot, cwd) {
|
|
146
|
+
return paths.length > 0 && paths.every((path) => isPathInsidePlannerRoot(path, plannerRoot, cwd));
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Which tool calls the guard covers, and what path(s) they would write to.
|
|
150
|
+
* Everything else (Read, Grep, WebFetch, MCP tools, read-only Bash, ...) is
|
|
151
|
+
* unguarded and returns `{ guarded: false }` without touching the planner
|
|
152
|
+
* store.
|
|
153
|
+
*/
|
|
154
|
+
export function classifyGuardedTool(event) {
|
|
155
|
+
if (GUARDED_FILE_TOOLS.has(event.toolName)) {
|
|
156
|
+
return { guarded: true, paths: event.filePath ? [event.filePath] : [] };
|
|
157
|
+
}
|
|
158
|
+
if (event.toolName === "NotebookEdit") {
|
|
159
|
+
return { guarded: true, paths: event.notebookPath ? [event.notebookPath] : [] };
|
|
160
|
+
}
|
|
161
|
+
if (event.toolName === "Bash") {
|
|
162
|
+
const command = event.command ?? "";
|
|
163
|
+
if (!isWriteShapedBashCommand(command))
|
|
164
|
+
return { guarded: false, paths: [] };
|
|
165
|
+
return { guarded: true, paths: extractBashWriteTargets(command) };
|
|
166
|
+
}
|
|
167
|
+
return { guarded: false, paths: [] };
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* The full "no task in progress" guard decision, as a pure function: given a
|
|
171
|
+
* parsed tool-use event and planner state the caller already fetched, decide
|
|
172
|
+
* allow or ask (deny is part of the type for a future genuinely-deny case,
|
|
173
|
+
* but nothing here returns it today). No stdin/stdout and no plan-store
|
|
174
|
+
* calls — the hook harness (or a Pi equivalent) does the reading and
|
|
175
|
+
* printing around this; the only filesystem access is the cheap symlink
|
|
176
|
+
* canonicalization in {@link isPathInsidePlannerRoot}.
|
|
177
|
+
*
|
|
178
|
+
* Order matters and mirrors the cost of finding out: anything the guard
|
|
179
|
+
* doesn't cover, and anything that resolves entirely inside the planner
|
|
180
|
+
* root, is decided from the event alone (no planner state needed). Only a
|
|
181
|
+
* real candidate for blocking reaches the state-based checks.
|
|
182
|
+
*/
|
|
183
|
+
export function decideGuardPreToolUse(event, state) {
|
|
184
|
+
const classification = classifyGuardedTool(event);
|
|
185
|
+
if (!classification.guarded)
|
|
186
|
+
return { decision: "allow" };
|
|
187
|
+
// Writing a handoff or recording task state is how an agent reports what
|
|
188
|
+
// it did, and it is most needed exactly when no task is in progress. Never
|
|
189
|
+
// block or ask for anything inside .planner/, regardless of task state.
|
|
190
|
+
if (isEntirelyInsidePlannerRoot(classification.paths, event.plannerRoot, event.cwd)) {
|
|
191
|
+
return { decision: "allow" };
|
|
192
|
+
}
|
|
193
|
+
if (!state.hasPlannerDir)
|
|
194
|
+
return { decision: "allow" };
|
|
195
|
+
if (state.totalTasks === 0)
|
|
196
|
+
return { decision: "allow" };
|
|
197
|
+
if (state.hasInProgressTask)
|
|
198
|
+
return { decision: "allow" };
|
|
199
|
+
if (state.guardBypassed)
|
|
200
|
+
return { decision: "allow" };
|
|
201
|
+
const reason = `Agent Plan guard: no task is in-progress, and this ${event.toolName} touches a file outside .planner/.${state.startHint} Or authorize a temporary bypass so this and further edits this session don't ask again (run /planner bypass, or call planner-authorize-bypass) — same bypass window an in-progress task already skips.`;
|
|
202
|
+
return { decision: "ask", reason };
|
|
203
|
+
}
|
|
@@ -124,12 +124,45 @@ export declare const HANDOFF_COLD_START_INVENTORY_CATEGORIES: readonly [{
|
|
|
124
124
|
export declare const HANDOFF_CANONICAL_SECTIONS: readonly ["Current focus", "Current and partial state", "Preservation constraints", "Supporting documents", "Blockers and risks", "How to resume"];
|
|
125
125
|
export type HandoffCompletenessCategory = typeof HANDOFF_COMPLETENESS_CATEGORIES[number]["id"];
|
|
126
126
|
export type HandoffColdStartInventoryCategory = typeof HANDOFF_COLD_START_INVENTORY_CATEGORIES[number]["id"];
|
|
127
|
-
export type HandoffContractErrorCode = "HANDOFF_PREFLIGHT_REQUIRED" | "HANDOFF_REASON_REQUIRED" | "HANDOFF_CANONICAL_SECTIONS_REQUIRED" | "HANDOFF_COMPLETENESS_AUDIT_REQUIRED" | "HANDOFF_COLD_START_INVENTORY_REQUIRED" | "HANDOFF_COLD_START_INVENTORY_UNCOVERED" | "HANDOFF_CONTENT_LIMIT_EXCEEDED" | "HANDOFF_SUPPORTING_DOCUMENT_INVALID" | "HANDOFF_PERSISTENCE_VERIFICATION_FAILED" | "HANDOFF_READBACK_VERIFICATION_REQUIRED" | "HANDOFF_READBACK_GAPS_FOUND";
|
|
127
|
+
export type HandoffContractErrorCode = "HANDOFF_PREFLIGHT_REQUIRED" | "HANDOFF_REASON_REQUIRED" | "HANDOFF_CANONICAL_SECTIONS_REQUIRED" | "HANDOFF_COMPLETENESS_AUDIT_REQUIRED" | "HANDOFF_COLD_START_INVENTORY_REQUIRED" | "HANDOFF_COLD_START_INVENTORY_UNCOVERED" | "HANDOFF_CONTENT_LIMIT_EXCEEDED" | "HANDOFF_SUPPORTING_DOCUMENT_INVALID" | "HANDOFF_PERSISTENCE_VERIFICATION_FAILED" | "HANDOFF_READBACK_VERIFICATION_REQUIRED" | "HANDOFF_READBACK_GAPS_FOUND" | "HANDOFF_RETAINED_CONTENT_NOT_FOUND" | "HANDOFF_SECTION_RECONCILIATION_REQUIRED";
|
|
128
128
|
export declare class HandoffContractError extends Error {
|
|
129
129
|
readonly code: HandoffContractErrorCode;
|
|
130
130
|
readonly details: Record<string, unknown>;
|
|
131
131
|
constructor(code: HandoffContractErrorCode, message: string, details?: Record<string, unknown>);
|
|
132
132
|
}
|
|
133
|
+
/** Single source of truth for the supportingDocuments recovery statement.
|
|
134
|
+
* Rendered in prepare output (before drafting) and attached to every
|
|
135
|
+
* agent-supplied-manifest failure of HANDOFF_SUPPORTING_DOCUMENT_INVALID
|
|
136
|
+
* (as details.recovery) so both adapters can render it without duplicating
|
|
137
|
+
* the wording. */
|
|
138
|
+
export declare const HANDOFF_SUPPORTING_DOCUMENTS_GUIDANCE = "supportingDocuments is optional and usually unnecessary: content above the target length is externalized automatically into .planner/docs/. Drop the field and retry unless you are linking a document you created yourself.";
|
|
139
|
+
/** Build a HANDOFF_SUPPORTING_DOCUMENT_INVALID error for a defect in an
|
|
140
|
+
* agent-supplied manifest entry, always carrying the droppable-field
|
|
141
|
+
* recovery statement. Do not use this for planner-owned failures (e.g. the
|
|
142
|
+
* auto-externalized document's own path) — those are not something dropping
|
|
143
|
+
* the agent's field would fix. */
|
|
144
|
+
export declare function supportingDocumentInvalidError(message: string, details?: Record<string, unknown>): HandoffContractError;
|
|
145
|
+
/** Build a HANDOFF_RETAINED_CONTENT_NOT_FOUND error: `content` was omitted
|
|
146
|
+
* from a handoff_write call and PlanStore has no body retained for this
|
|
147
|
+
* phase + expectedHandoffUpdatedAt token (see PlanStore.retainHandoffDraft /
|
|
148
|
+
* getRetainedHandoffDraft). Reasons: no write against this token has ever
|
|
149
|
+
* failed, the retained draft aged out, the phase went terminal and its
|
|
150
|
+
* drafts were discarded, or the token itself is wrong/stale. Content is
|
|
151
|
+
* always required on the first write attempt for a token; it becomes
|
|
152
|
+
* optional only on a retry that reuses a retained one. */
|
|
153
|
+
export declare function retainedHandoffContentNotFoundError(phaseId: string, expectedHandoffUpdatedAt: string): HandoffContractError;
|
|
154
|
+
/** One prior section's fate, supplied by the author when validateHandoffSectionReconciliation
|
|
155
|
+
* names it as unaccounted for. `section` must match a heading named in the
|
|
156
|
+
* error's `unaccountedSections`; `disposition` is a short, substantive
|
|
157
|
+
* statement of what happened to it — dropped deliberately, superseded by
|
|
158
|
+
* newer content, or folded into a different section (including a rename).
|
|
159
|
+
* See P104(F005)/T416: this is the evidence that replaces the unchecked
|
|
160
|
+
* `reconciledExistingHandoff` boolean for the sections most likely to be
|
|
161
|
+
* silently lost. */
|
|
162
|
+
export interface HandoffSectionDispositionInput {
|
|
163
|
+
section: string;
|
|
164
|
+
disposition: string;
|
|
165
|
+
}
|
|
133
166
|
export interface HandoffCompletenessAuditInput {
|
|
134
167
|
version: number;
|
|
135
168
|
entries: HandoffCompletenessEntry[];
|
|
@@ -152,6 +185,64 @@ export interface HandoffContentExternalization {
|
|
|
152
185
|
extendedContent: string;
|
|
153
186
|
supportingDocument?: HandoffSupportingDocumentInput;
|
|
154
187
|
}
|
|
188
|
+
/** One document that a previous handoff refresh moved out of the inline
|
|
189
|
+
* capsule because it exceeded TARGET_HANDOFF_CONTENT_CHARS. Populated by
|
|
190
|
+
* PlanStore.preparePhaseHandoff (which alone has filesystem access); pure
|
|
191
|
+
* code here only shapes the type and the recognition/heading helpers below.
|
|
192
|
+
* `headings` and `missing` are always meaningful even when `content` is
|
|
193
|
+
* omitted for budget reasons, so a caller who cannot inline the body can
|
|
194
|
+
* still name what it contained (see handoff-reply.ts). */
|
|
195
|
+
export interface HandoffExternalizedDocumentAudit {
|
|
196
|
+
path: string;
|
|
197
|
+
description: string;
|
|
198
|
+
/** Level-2 (`##`) headings found in the document, in order. Present even
|
|
199
|
+
* when `content` is null, so the omission names what the document held. */
|
|
200
|
+
headings: string[];
|
|
201
|
+
/** Full document body, or null when it could not be read back from disk
|
|
202
|
+
* (deleted, moved, or unreadable). Bounding this for transport is the
|
|
203
|
+
* reply builder's job (handoff-reply.ts), not this audit's. */
|
|
204
|
+
content: string | null;
|
|
205
|
+
contentLength: number;
|
|
206
|
+
missing: boolean;
|
|
207
|
+
}
|
|
208
|
+
/** The exact description externalizeOversizedHandoffContent stamps on the
|
|
209
|
+
* supporting-document entry it generates for an auto-externalized document.
|
|
210
|
+
* The single source of truth for recognizing one later: handoff_prepare
|
|
211
|
+
* matches on this instead of the timestamped file-naming convention, so
|
|
212
|
+
* detection and generation cannot drift apart. A document a human or agent
|
|
213
|
+
* linked deliberately (a different description) is already named in the
|
|
214
|
+
* persisted capsule's own "Supporting documents" bullet and is out of scope
|
|
215
|
+
* here — only content the tooling itself moved out without being asked. */
|
|
216
|
+
export declare const HANDOFF_AUTO_EXTERNALIZED_DOCUMENT_DESCRIPTION = "Full submitted handoff detail externalized automatically; required for cold resume and reconciliation.";
|
|
217
|
+
export declare function isAutoExternalizedHandoffDocument(document: {
|
|
218
|
+
description: string;
|
|
219
|
+
}): boolean;
|
|
220
|
+
/** Level-2 (`##`) headings of a handoff document, in order. Used to name
|
|
221
|
+
* what an externalized document contains when its content cannot be
|
|
222
|
+
* inlined (budget, or the file is missing) and as a table of contents
|
|
223
|
+
* alongside content that is inlined. */
|
|
224
|
+
export declare function extractHandoffSectionHeadings(content: string): string[];
|
|
225
|
+
/**
|
|
226
|
+
* Make reconciliation evidenced rather than asserted (P104(F005)/T416).
|
|
227
|
+
*
|
|
228
|
+
* Narrow by design: this compares `##` heading text only, never section
|
|
229
|
+
* content or a fixed category list — it is not a return to the 16-section
|
|
230
|
+
* scaffold and 14-category cold-start inventory P100(F021)/T396 removed for
|
|
231
|
+
* making authoring verbose and failing late. A prior capsule with no
|
|
232
|
+
* headings (or a new submission with none) simply has nothing to name here;
|
|
233
|
+
* the check degrades to a no-op rather than blocking the write.
|
|
234
|
+
*
|
|
235
|
+
* A prior section vanishes from the new content in three ways an author
|
|
236
|
+
* might legitimately intend: dropped because it no longer matters,
|
|
237
|
+
* superseded by newer content, or folded into a different section (a rename
|
|
238
|
+
* reads the same way — the old heading is gone, the content lives under a
|
|
239
|
+
* new one). This function does not try to tell those apart; it only
|
|
240
|
+
* requires the author to say which happened, per named section, before the
|
|
241
|
+
* write proceeds. A deliberate full rewrite where every prior section is
|
|
242
|
+
* obsolete is handled the same way: every heading is named, and the author
|
|
243
|
+
* writes one disposition per heading.
|
|
244
|
+
*/
|
|
245
|
+
export declare function validateHandoffSectionReconciliation(priorSectionHeadings: string[], newContent: string, dispositions: HandoffSectionDispositionInput[] | undefined): void;
|
|
155
246
|
export interface HandoffTaskContextUpdate {
|
|
156
247
|
taskId: string;
|
|
157
248
|
completionSummary: string;
|
|
@@ -212,6 +303,27 @@ export interface PhaseHandoffAudit {
|
|
|
212
303
|
}>;
|
|
213
304
|
existingCompletenessAudit: HandoffCompletenessAudit | null;
|
|
214
305
|
phaseWorkMap: PhaseWorkMap;
|
|
306
|
+
/** Read before drafting: supportingDocuments is optional and rarely needed. */
|
|
307
|
+
supportingDocumentsGuidance: string;
|
|
308
|
+
/** Documents the existing active handoff's own auto-externalization moved
|
|
309
|
+
* out of the inline capsule (see HANDOFF_AUTO_EXTERNALIZED_DOCUMENT_DESCRIPTION).
|
|
310
|
+
* Empty when there is no active handoff or nothing was ever externalized
|
|
311
|
+
* from it. auditPhaseHandoff itself never populates this (it is pure and
|
|
312
|
+
* has no filesystem access) — PlanStore.preparePhaseHandoff fills it in
|
|
313
|
+
* after reading each document back from .planner/docs/. */
|
|
314
|
+
externalizedHandoffDocuments: HandoffExternalizedDocumentAudit[];
|
|
315
|
+
/** `##` headings of the full prior capsule the next write will supersede:
|
|
316
|
+
* the active handoff's own headings plus, per P104(F005)/T415, the
|
|
317
|
+
* headings of every document its own auto-externalization moved out —
|
|
318
|
+
* never the elided copy, so a heading that survives only in the
|
|
319
|
+
* externalized file is still named. Empty when there is no active
|
|
320
|
+
* handoff to reconcile against (first write, or one already archived by
|
|
321
|
+
* handoff_clear). auditPhaseHandoff itself only derives this from the
|
|
322
|
+
* compact capsule text (no filesystem access); PlanStore.preparePhaseHandoff
|
|
323
|
+
* and PlanStore.refreshPhaseHandoff both overlay the externalized
|
|
324
|
+
* documents' own headings after reading them back. See
|
|
325
|
+
* validateHandoffSectionReconciliation, which consumes this list. */
|
|
326
|
+
priorSectionHeadings: string[];
|
|
215
327
|
}
|
|
216
328
|
export interface RefreshPhaseHandoffInput {
|
|
217
329
|
/** Structured, human-supplied explanation; rendered by the planner. */
|
|
@@ -219,9 +331,26 @@ export interface RefreshPhaseHandoffInput {
|
|
|
219
331
|
content: string;
|
|
220
332
|
expectedHandoffUpdatedAt: string;
|
|
221
333
|
reconciledExistingHandoff: boolean;
|
|
334
|
+
/** The full prior capsule's `##` headings (see PhaseHandoffAudit.priorSectionHeadings),
|
|
335
|
+
* as PlanStore derived them from the live phase this write is targeting —
|
|
336
|
+
* never a stale copy captured at prepare time, so a handoff archived
|
|
337
|
+
* between prepare and write (phase.handoff now "") correctly yields no
|
|
338
|
+
* sections to reconcile instead of demanding dispositions for content
|
|
339
|
+
* that is no longer live. Populated by PlanStore; absent only in direct
|
|
340
|
+
* unit calls to applyHandoffContextSync/validateHandoffContextSync that
|
|
341
|
+
* do not exercise this check. */
|
|
342
|
+
priorSectionHeadings?: string[];
|
|
343
|
+
/** Per-section account for each entry in priorSectionHeadings that has no
|
|
344
|
+
* counterpart heading in the submitted content. See
|
|
345
|
+
* validateHandoffSectionReconciliation. */
|
|
346
|
+
sectionDispositions?: HandoffSectionDispositionInput[];
|
|
222
347
|
completenessAudit?: HandoffCompletenessAuditInput;
|
|
223
348
|
coldStartInventory?: HandoffColdStartInventoryInput;
|
|
224
349
|
supportingDocuments?: HandoffSupportingDocumentInput[];
|
|
350
|
+
/** The body exactly as the agent submitted it, before auto-externalization
|
|
351
|
+
* rewrote `content`. Set by PlanStore only when a rewrite happened, so the
|
|
352
|
+
* agent's own document links are still judged against what the agent wrote. */
|
|
353
|
+
submittedContent?: string;
|
|
225
354
|
/** Populated and verified by PlanStore before pure domain application. */
|
|
226
355
|
verifiedSupportingDocuments?: HandoffSupportingDocument[];
|
|
227
356
|
/** Content is kept in-memory only for cold-start coverage validation. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handoff-context.d.ts","sourceRoot":"","sources":["../src/handoff-context.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,OAAO,EACP,wBAAwB,EACxB,wBAAwB,EACxB,8BAA8B,EAC9B,yBAAyB,EACzB,KAAK,EACL,IAAI,EACL,MAAM,aAAa,CAAC;AACrB,OAAO,EAAqB,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"handoff-context.d.ts","sourceRoot":"","sources":["../src/handoff-context.ts"],"names":[],"mappings":"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"}
|