@agent-plan/core 0.2.23 → 0.2.25

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.
@@ -0,0 +1,60 @@
1
+ import type { Feature, Phase, Task } from "./schema.js";
2
+ export declare const COMPLETION_SUMMARY_HEADING = "**Completion summary:**";
3
+ export interface HandoffTaskContextUpdate {
4
+ taskId: string;
5
+ completionSummary: string;
6
+ verification: string;
7
+ remainingWork: string;
8
+ filesTouched?: string[];
9
+ decisions?: string[];
10
+ }
11
+ export interface HandoffPhaseContextUpdate {
12
+ progressSummary: string;
13
+ remainingWork: string;
14
+ decisions?: string[];
15
+ }
16
+ export interface HandoffFeatureContextUpdate {
17
+ workDone: string;
18
+ workRemaining: string;
19
+ }
20
+ export interface PhaseHandoffContextSync {
21
+ taskUpdates: HandoffTaskContextUpdate[];
22
+ phaseUpdate?: HandoffPhaseContextUpdate;
23
+ phaseNoUpdateReason?: string;
24
+ featureUpdate?: HandoffFeatureContextUpdate;
25
+ featureNoUpdateReason?: string;
26
+ }
27
+ export interface PhaseHandoffAudit {
28
+ phaseId: string;
29
+ featureId: string;
30
+ handoff: string;
31
+ handoffUpdatedAt: string;
32
+ missingCompletionTaskIds: string[];
33
+ missingCompletionTasks: Array<{
34
+ id: string;
35
+ number: number;
36
+ title: string;
37
+ }>;
38
+ }
39
+ export interface RefreshPhaseHandoffInput {
40
+ content: string;
41
+ expectedHandoffUpdatedAt: string;
42
+ reconciledExistingHandoff: boolean;
43
+ contextSync: PhaseHandoffContextSync;
44
+ }
45
+ export interface RefreshPhaseHandoffResult {
46
+ phase: Phase;
47
+ feature: Feature;
48
+ updatedTaskIds: string[];
49
+ handoffUpdatedAt: string;
50
+ }
51
+ export declare function hasTaskCompletionEvidence(task: Task): boolean;
52
+ export declare function auditPhaseHandoff(phase: Phase, feature: Feature): PhaseHandoffAudit;
53
+ export declare function validateCanonicalHandoffContent(content: string): void;
54
+ export declare function validateHandoffContextSync(phase: Phase, feature: Feature, input: RefreshPhaseHandoffInput): void;
55
+ export declare function applyHandoffContextSync(phase: Phase, feature: Feature, input: RefreshPhaseHandoffInput, timestamp: string): {
56
+ phase: Phase;
57
+ feature: Feature;
58
+ updatedTaskIds: string[];
59
+ };
60
+ //# sourceMappingURL=handoff-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handoff-context.d.ts","sourceRoot":"","sources":["../src/handoff-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAExD,eAAO,MAAM,0BAA0B,4BAA4B,CAAC;AAEpE,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,yBAAyB;IACxC,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,uBAAuB;IACtC,WAAW,EAAE,wBAAwB,EAAE,CAAC;IACxC,WAAW,CAAC,EAAE,yBAAyB,CAAC;IACxC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,aAAa,CAAC,EAAE,2BAA2B,CAAC;IAC5C,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,EAAE,MAAM,CAAC;IACzB,wBAAwB,EAAE,MAAM,EAAE,CAAC;IACnC,sBAAsB,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC9E;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,wBAAwB,EAAE,MAAM,CAAC;IACjC,yBAAyB,EAAE,OAAO,CAAC;IACnC,WAAW,EAAE,uBAAuB,CAAC;CACtC;AAED,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,KAAK,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAI7D;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,GAAG,iBAAiB,CAYnF;AAkBD,wBAAgB,+BAA+B,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAgBrE;AAED,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,wBAAwB,GAC9B,IAAI,CA4CN;AAED,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,wBAAwB,EAC/B,SAAS,EAAE,MAAM,GAChB;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,cAAc,EAAE,MAAM,EAAE,CAAA;CAAE,CAqD9D"}
@@ -0,0 +1,150 @@
1
+ export const COMPLETION_SUMMARY_HEADING = "**Completion summary:**";
2
+ export function hasTaskCompletionEvidence(task) {
3
+ if (task.status !== "done")
4
+ return true;
5
+ if (task.description.includes(COMPLETION_SUMMARY_HEADING))
6
+ return true;
7
+ return task.statusLog.some((entry) => entry.toStatus === "done" && entry.description.trim().length > 0);
8
+ }
9
+ export function auditPhaseHandoff(phase, feature) {
10
+ const missingCompletionTasks = phase.tasks
11
+ .filter((task) => task.status === "done" && !hasTaskCompletionEvidence(task))
12
+ .map((task) => ({ id: task.id, number: task.number, title: task.title }));
13
+ return {
14
+ phaseId: phase.id,
15
+ featureId: feature.id,
16
+ handoff: phase.handoff,
17
+ handoffUpdatedAt: phase.handoffUpdatedAt,
18
+ missingCompletionTaskIds: missingCompletionTasks.map((task) => task.id),
19
+ missingCompletionTasks,
20
+ };
21
+ }
22
+ function nonEmpty(value, field) {
23
+ const normalized = value?.trim() ?? "";
24
+ if (!normalized)
25
+ throw new Error(`${field} is required.`);
26
+ return normalized;
27
+ }
28
+ function uniqueStrings(values) {
29
+ return [...new Set(values.map((value) => value.trim()).filter(Boolean))];
30
+ }
31
+ function appendSection(existing, section) {
32
+ const normalized = section.trim();
33
+ if (!normalized || existing.includes(normalized))
34
+ return existing;
35
+ return existing.trim() ? `${existing.trim()}\n\n---\n${normalized}` : normalized;
36
+ }
37
+ export function validateCanonicalHandoffContent(content) {
38
+ const body = nonEmpty(content, "Handoff content");
39
+ const required = [
40
+ { label: "Created at", pattern: /^Created at:\s*\S+/im },
41
+ { label: "Updated at", pattern: /^Updated at:\s*\S+/im },
42
+ { label: "Reason", pattern: /^Reason:\s*\S+/im },
43
+ { label: "Current focus", pattern: /^##\s+Current focus\s*$/im },
44
+ { label: "What was being done", pattern: /^##\s+What was being done\s*$/im },
45
+ { label: "How to resume", pattern: /^##\s+How to resume\s*$/im },
46
+ { label: "Files touched", pattern: /^##\s+Files touched\s*$/im },
47
+ { label: "Blockers", pattern: /^##\s+Blockers\s*$/im },
48
+ { label: "Next steps", pattern: /^##\s+Next steps\s*$/im },
49
+ { label: "Recent decisions", pattern: /^##\s+Recent decisions\s*$/im },
50
+ ];
51
+ const missing = required.filter((entry) => !entry.pattern.test(body)).map((entry) => entry.label);
52
+ if (missing.length > 0)
53
+ throw new Error(`Canonical handoff is missing required sections: ${missing.join(", ")}.`);
54
+ }
55
+ export function validateHandoffContextSync(phase, feature, input) {
56
+ validateCanonicalHandoffContent(input.content);
57
+ if (phase.status === "done" || phase.status === "canceled") {
58
+ throw new Error(`Cannot write a handoff on ${phase.status} phase ${phase.id}; completed phases have no pending handoff.`);
59
+ }
60
+ if (phase.handoffUpdatedAt !== input.expectedHandoffUpdatedAt) {
61
+ throw new Error("Handoff changed after preparation. Run handoff_prepare again and reconcile the latest content before writing.");
62
+ }
63
+ if (phase.handoff.trim() && !input.reconciledExistingHandoff) {
64
+ throw new Error("An active handoff already exists. Reconcile its still-relevant content and set reconciledExistingHandoff=true.");
65
+ }
66
+ const sync = input.contextSync;
67
+ const taskIds = sync.taskUpdates.map((update) => nonEmpty(update.taskId, "Task update taskId"));
68
+ if (new Set(taskIds).size !== taskIds.length)
69
+ throw new Error("Each task may appear only once in handoff context updates.");
70
+ const phaseTaskIds = new Set(phase.tasks.map((task) => task.id));
71
+ for (const taskId of taskIds) {
72
+ if (!phaseTaskIds.has(taskId))
73
+ throw new Error(`Task ${taskId} does not belong to phase ${phase.id}.`);
74
+ }
75
+ for (const update of sync.taskUpdates) {
76
+ nonEmpty(update.completionSummary, `Task ${update.taskId} completionSummary`);
77
+ nonEmpty(update.verification, `Task ${update.taskId} verification`);
78
+ nonEmpty(update.remainingWork, `Task ${update.taskId} remainingWork`);
79
+ }
80
+ const audit = auditPhaseHandoff(phase, feature);
81
+ const covered = new Set(taskIds);
82
+ const uncovered = audit.missingCompletionTaskIds.filter((taskId) => !covered.has(taskId));
83
+ if (uncovered.length > 0) {
84
+ throw new Error(`Done tasks are missing durable completion evidence: ${uncovered.join(", ")}. Include context updates for every listed task.`);
85
+ }
86
+ if (sync.phaseUpdate) {
87
+ nonEmpty(sync.phaseUpdate.progressSummary, "Phase progressSummary");
88
+ nonEmpty(sync.phaseUpdate.remainingWork, "Phase remainingWork");
89
+ }
90
+ else {
91
+ nonEmpty(sync.phaseNoUpdateReason, "phaseNoUpdateReason");
92
+ }
93
+ if (sync.featureUpdate) {
94
+ nonEmpty(sync.featureUpdate.workDone, "Feature workDone");
95
+ nonEmpty(sync.featureUpdate.workRemaining, "Feature workRemaining");
96
+ }
97
+ else {
98
+ nonEmpty(sync.featureNoUpdateReason, "featureNoUpdateReason");
99
+ }
100
+ }
101
+ export function applyHandoffContextSync(phase, feature, input, timestamp) {
102
+ validateHandoffContextSync(phase, feature, input);
103
+ const nextPhase = structuredClone(phase);
104
+ const nextFeature = structuredClone(feature);
105
+ const updatedTaskIds = [];
106
+ for (const update of input.contextSync.taskUpdates) {
107
+ const task = nextPhase.tasks.find((candidate) => candidate.id === update.taskId);
108
+ const files = uniqueStrings(update.filesTouched ?? []);
109
+ const decisions = uniqueStrings(update.decisions ?? []);
110
+ const section = [
111
+ COMPLETION_SUMMARY_HEADING,
112
+ update.completionSummary.trim(),
113
+ "",
114
+ "**Verification:**",
115
+ update.verification.trim(),
116
+ "",
117
+ "**Remaining or unverified:**",
118
+ update.remainingWork.trim(),
119
+ ...(files.length > 0 ? ["", "**Files touched:**", ...files.map((file) => `- ${file}`)] : []),
120
+ ].join("\n");
121
+ task.description = appendSection(task.description, section);
122
+ task.descriptionUpdatedAt = timestamp;
123
+ task.decisions = uniqueStrings([...(task.decisions ?? []), ...decisions]);
124
+ task.updatedAt = timestamp;
125
+ updatedTaskIds.push(task.id);
126
+ }
127
+ const phaseUpdate = input.contextSync.phaseUpdate;
128
+ if (phaseUpdate) {
129
+ const section = [
130
+ "**Handoff context update:**",
131
+ phaseUpdate.progressSummary.trim(),
132
+ "",
133
+ "**Remaining work:**",
134
+ phaseUpdate.remainingWork.trim(),
135
+ ].join("\n");
136
+ nextPhase.notes = appendSection(nextPhase.notes, section);
137
+ nextPhase.decisions = uniqueStrings([...(nextPhase.decisions ?? []), ...(phaseUpdate.decisions ?? [])]);
138
+ }
139
+ const featureUpdate = input.contextSync.featureUpdate;
140
+ if (featureUpdate) {
141
+ nextFeature.workDone = appendSection(nextFeature.workDone, featureUpdate.workDone);
142
+ nextFeature.workRemaining = appendSection(nextFeature.workRemaining, featureUpdate.workRemaining);
143
+ }
144
+ nextPhase.handoff = input.content.trim();
145
+ nextPhase.handoffUpdatedAt = timestamp;
146
+ nextPhase.handoffReadAt = "";
147
+ nextPhase.updatedAt = timestamp;
148
+ nextFeature.updatedAt = timestamp;
149
+ return { phase: nextPhase, feature: nextFeature, updatedTaskIds };
150
+ }
package/dist/index.d.ts CHANGED
@@ -7,7 +7,9 @@ export * from "./planner-rules.js";
7
7
  export * from "./display-status.js";
8
8
  export * from "./task-context.js";
9
9
  export * from "./task-selection.js";
10
+ export * from "./task-start-outcome.js";
10
11
  export * from "./read-tracking.js";
12
+ export * from "./handoff-context.js";
11
13
  export * from "./package-version.js";
12
14
  export { PlanStore, PlanStoreError, setWriteBusyHook, setWriteNotifyHook, migrateToUuids, migrateToGlobalSequence, withFeatureLock, type PhaseHandoffSummary, type OrphanPhaseSummary } from "./plan-store.js";
13
15
  export { PlanRenderer } from "./renderer.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,cAAc,EAAE,uBAAuB,EAAE,eAAe,EAAE,KAAK,mBAAmB,EAAE,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC/M,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,YAAY,EAAE,eAAe,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,cAAc,EAAE,uBAAuB,EAAE,eAAe,EAAE,KAAK,mBAAmB,EAAE,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC/M,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,YAAY,EAAE,eAAe,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.js CHANGED
@@ -7,7 +7,9 @@ export * from "./planner-rules.js";
7
7
  export * from "./display-status.js";
8
8
  export * from "./task-context.js";
9
9
  export * from "./task-selection.js";
10
+ export * from "./task-start-outcome.js";
10
11
  export * from "./read-tracking.js";
12
+ export * from "./handoff-context.js";
11
13
  export * from "./package-version.js";
12
14
  export { PlanStore, PlanStoreError, setWriteBusyHook, setWriteNotifyHook, migrateToUuids, migrateToGlobalSequence, withFeatureLock } from "./plan-store.js";
13
15
  export { PlanRenderer } from "./renderer.js";
@@ -1,6 +1,21 @@
1
1
  import { z } from "zod";
2
2
  import { type Feature, type FeaturesDocument, type Manifest, type Phase, type Task, type TaskPauseSnapshot, type PlanWorkspace, type Project, type RequirementsDocument, type Requirement, type ActivityEntry, type ActivityLog, type CodebaseProfile, type ResumeFocus, type WorkDeviation } from "./schema.js";
3
3
  import { type ParentDisplay } from "./display-status.js";
4
+ import { type PhaseHandoffAudit, type RefreshPhaseHandoffInput, type RefreshPhaseHandoffResult } from "./handoff-context.js";
5
+ export interface RecordContextReadInput {
6
+ sessionId: string;
7
+ phaseId: string;
8
+ taskId: string;
9
+ featureId?: string;
10
+ requirementIds?: string[];
11
+ createdAt?: string;
12
+ }
13
+ export interface RecordContextReadResult {
14
+ phase: Phase;
15
+ feature?: Feature;
16
+ requirements: Requirement[];
17
+ createdAt: string;
18
+ }
4
19
  export interface PlanStoreErrorDetails {
5
20
  path?: string;
6
21
  operation?: string;
@@ -338,6 +353,12 @@ export declare class PlanStore {
338
353
  setWorkDeviationState(id: string, state: "active" | "resume-required" | "resolved" | "resumed" | "canceled", timestamp?: string): Promise<Project>;
339
354
  updateFeatures(updater: (f: FeaturesDocument) => FeaturesDocument): Promise<FeaturesDocument>;
340
355
  updateRequirements(updater: (r: RequirementsDocument) => RequirementsDocument): Promise<RequirementsDocument>;
356
+ /**
357
+ * Persist completion of one full task → phase → feature → requirements read
358
+ * sequence. Session metadata is deliberately the only changed entity field:
359
+ * semantic updatedAt/descriptionUpdatedAt values are preserved exactly.
360
+ */
361
+ recordContextRead(input: RecordContextReadInput): Promise<RecordContextReadResult>;
341
362
  saveProject(project: Project): Promise<void>;
342
363
  saveFeatures(features: FeaturesDocument): Promise<void>;
343
364
  /** Per-file write of all features + orphan reconcile. No lock (caller holds withFeaturesLock). */
@@ -356,6 +377,13 @@ export declare class PlanStore {
356
377
  resumeTask(phaseId: string, taskId: string, timestamp?: string): Promise<Task>;
357
378
  /** Get the handoff text for a phase ("" if none). Throws if phase missing. */
358
379
  getPhaseHandoff(phaseId: string): Promise<string>;
380
+ /** Audit one exact phase before preparing a handoff refresh. */
381
+ preparePhaseHandoff(phaseId: string): Promise<PhaseHandoffAudit>;
382
+ /** Refresh the single active handoff and synchronize durable task/phase/feature
383
+ * context. Unlike setPhaseHandoff(), this deliberately does not archive the
384
+ * previous active body: callers must reconcile it using the optimistic
385
+ * handoffUpdatedAt token returned by preparePhaseHandoff(). */
386
+ refreshPhaseHandoff(phaseId: string, input: RefreshPhaseHandoffInput): Promise<RefreshPhaseHandoffResult>;
359
387
  /** Set the handoff text for a phase + stamp handoffUpdatedAt. A completed or
360
388
  * canceled phase cannot receive a new operational handoff. Replacing an
361
389
  * existing handoff archives the previous content as `superseded` first. */
@@ -1 +1 @@
1
- {"version":3,"file":"plan-store.d.ts","sourceRoot":"","sources":["../src/plan-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"plan-store.d.ts","sourceRoot":"","sources":["../src/plan-store.ts"],"names":[],"mappings":"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"}
@@ -18,9 +18,22 @@ import { CodebaseProfileSchema, FeatureSchema, FeaturesDocumentSchema, ManifestS
18
18
  import { createFeatureId, createPhaseId, createRequirementId, createShortId, createStatusLogEntryId, createTaskId, formatPhaseRef, isLegacyPhaseId } from "./naming.js";
19
19
  import { deriveParentDisplay, fromCanonicalStatus } from "./display-status.js";
20
20
  import { loadExtensionRules, PLANNER_EXTENSION_RULES } from "./planner-rules.js";
21
+ import { applyHandoffContextSync, auditPhaseHandoff, } from "./handoff-context.js";
21
22
  function nowISO() {
22
23
  return new Date().toISOString();
23
24
  }
25
+ const MAX_SESSION_INFO_ENTRIES = 16;
26
+ function upsertSessionInfo(entity, sessionId, createdAt) {
27
+ const nextInfo = [
28
+ ...entity.sessionInfo.filter((entry) => entry.sessionId !== sessionId),
29
+ { sessionId, createdAt },
30
+ ]
31
+ .sort((left, right) => right.createdAt.localeCompare(left.createdAt))
32
+ .slice(0, MAX_SESSION_INFO_ENTRIES);
33
+ const changed = nextInfo.length !== entity.sessionInfo.length
34
+ || nextInfo.some((entry, index) => entry.sessionId !== entity.sessionInfo[index]?.sessionId || entry.createdAt !== entity.sessionInfo[index]?.createdAt);
35
+ return changed ? { entity: { ...entity, sessionInfo: nextInfo }, changed: true } : { entity, changed: false };
36
+ }
24
37
  function resolveStoredFeatureId(features, ref) {
25
38
  const raw = ref?.trim();
26
39
  if (!raw)
@@ -1942,6 +1955,90 @@ export class PlanStore {
1942
1955
  await this.maybeAutoSync();
1943
1956
  return updated;
1944
1957
  }
1958
+ /**
1959
+ * Persist completion of one full task → phase → feature → requirements read
1960
+ * sequence. Session metadata is deliberately the only changed entity field:
1961
+ * semantic updatedAt/descriptionUpdatedAt values are preserved exactly.
1962
+ */
1963
+ async recordContextRead(input) {
1964
+ const sessionId = input.sessionId.trim();
1965
+ if (!sessionId)
1966
+ throw new PlanStoreError("Context-read attestation requires a non-empty sessionId.");
1967
+ const createdAt = TimestampSchema.parse(input.createdAt ?? nowISO());
1968
+ const requirementIds = [...new Set((input.requirementIds ?? []).map((id) => id.trim()).filter(Boolean))];
1969
+ return this.runAsBatch(async () => {
1970
+ const originalPhase = await this.loadPhase(input.phaseId);
1971
+ const taskIndex = originalPhase.tasks.findIndex((task) => task.id === input.taskId);
1972
+ if (taskIndex < 0)
1973
+ throw new PlanStoreError(`Task ${input.taskId} does not belong to phase ${input.phaseId}.`);
1974
+ const originalFeatures = await this.loadFeatures();
1975
+ const featureId = input.featureId?.trim() || originalPhase.featureId;
1976
+ const featureIndex = featureId
1977
+ ? originalFeatures.features.findIndex((feature) => feature.id === featureId)
1978
+ : -1;
1979
+ if (featureId && featureIndex < 0)
1980
+ throw new PlanStoreError(`Feature ${featureId} was not found for context-read attestation.`);
1981
+ const originalRequirements = await this.loadRequirements();
1982
+ const missingRequirement = requirementIds.find((id) => !originalRequirements.requirements.some((requirement) => requirement.id === id));
1983
+ if (missingRequirement)
1984
+ throw new PlanStoreError(`Requirement ${missingRequirement} was not found for context-read attestation.`);
1985
+ const nextPhase = structuredClone(originalPhase);
1986
+ const nextTask = upsertSessionInfo(nextPhase.tasks[taskIndex], sessionId, createdAt);
1987
+ nextPhase.tasks[taskIndex] = nextTask.entity;
1988
+ const nextPhaseInfo = upsertSessionInfo(nextPhase, sessionId, createdAt);
1989
+ const phaseChanged = nextTask.changed || nextPhaseInfo.changed;
1990
+ let nextFeature;
1991
+ let featureChanged = false;
1992
+ if (featureIndex >= 0) {
1993
+ const featureResult = upsertSessionInfo(structuredClone(originalFeatures.features[featureIndex]), sessionId, createdAt);
1994
+ nextFeature = featureResult.entity;
1995
+ featureChanged = featureResult.changed;
1996
+ }
1997
+ const nextRequirements = structuredClone(originalRequirements);
1998
+ let requirementsChanged = false;
1999
+ for (const requirement of nextRequirements.requirements) {
2000
+ if (!requirementIds.includes(requirement.id))
2001
+ continue;
2002
+ const result = upsertSessionInfo(requirement, sessionId, createdAt);
2003
+ if (result.changed) {
2004
+ Object.assign(requirement, result.entity);
2005
+ requirementsChanged = true;
2006
+ }
2007
+ }
2008
+ if (!phaseChanged && !featureChanged && !requirementsChanged) {
2009
+ return {
2010
+ phase: originalPhase,
2011
+ ...(featureIndex >= 0 ? { feature: originalFeatures.features[featureIndex] } : {}),
2012
+ requirements: originalRequirements.requirements.filter((requirement) => requirementIds.includes(requirement.id)),
2013
+ createdAt,
2014
+ };
2015
+ }
2016
+ try {
2017
+ if (featureChanged && nextFeature)
2018
+ await this.saveFeature(nextFeature);
2019
+ if (phaseChanged)
2020
+ await this.savePhase(nextPhaseInfo.entity);
2021
+ if (requirementsChanged)
2022
+ await this.saveRequirements(nextRequirements);
2023
+ }
2024
+ catch (error) {
2025
+ const rollbackErrors = [];
2026
+ if (featureChanged && nextFeature)
2027
+ await this.saveFeature(originalFeatures.features[featureIndex]).catch((rollbackError) => rollbackErrors.push(rollbackError));
2028
+ if (phaseChanged)
2029
+ await this.savePhase(originalPhase).catch((rollbackError) => rollbackErrors.push(rollbackError));
2030
+ if (requirementsChanged)
2031
+ await this.saveRequirements(originalRequirements).catch((rollbackError) => rollbackErrors.push(rollbackError));
2032
+ if (rollbackErrors.length > 0)
2033
+ throw new AggregateError([error, ...rollbackErrors], "Context-read attestation failed and rollback was incomplete.");
2034
+ throw error;
2035
+ }
2036
+ const phase = await this.loadPhase(input.phaseId);
2037
+ const feature = featureIndex >= 0 ? (await this.loadFeatures()).features.find((candidate) => candidate.id === featureId) : undefined;
2038
+ const requirements = (await this.loadRequirements()).requirements.filter((requirement) => requirementIds.includes(requirement.id));
2039
+ return { phase, ...(feature ? { feature } : {}), requirements, createdAt };
2040
+ });
2041
+ }
1945
2042
  async saveProject(project) {
1946
2043
  // Runtime workDeviations live in .local/deviations.json (T299); never
1947
2044
  // persist them here so shared project.json stays stable across worktrees.
@@ -2138,6 +2235,51 @@ export class PlanStore {
2138
2235
  async getPhaseHandoff(phaseId) {
2139
2236
  return (await this.loadPhase(phaseId)).handoff;
2140
2237
  }
2238
+ /** Audit one exact phase before preparing a handoff refresh. */
2239
+ async preparePhaseHandoff(phaseId) {
2240
+ const phase = await this.loadPhase(phaseId);
2241
+ if (!phase.featureId)
2242
+ throw new PlanStoreError(`Phase ${phaseId} has no parent feature; durable handoff context cannot be synchronized.`);
2243
+ const feature = (await this.loadFeatures()).features.find((candidate) => candidate.id === phase.featureId);
2244
+ if (!feature)
2245
+ throw new PlanStoreError(`Parent feature ${phase.featureId} not found for phase ${phaseId}.`);
2246
+ return auditPhaseHandoff(phase, feature);
2247
+ }
2248
+ /** Refresh the single active handoff and synchronize durable task/phase/feature
2249
+ * context. Unlike setPhaseHandoff(), this deliberately does not archive the
2250
+ * previous active body: callers must reconcile it using the optimistic
2251
+ * handoffUpdatedAt token returned by preparePhaseHandoff(). */
2252
+ async refreshPhaseHandoff(phaseId, input) {
2253
+ return this.runAsBatch(async () => {
2254
+ const originalPhase = await this.loadPhase(phaseId);
2255
+ if (!originalPhase.featureId)
2256
+ throw new PlanStoreError(`Phase ${phaseId} has no parent feature; durable handoff context cannot be synchronized.`);
2257
+ const originalFeatures = await this.loadFeatures();
2258
+ const featureIndex = originalFeatures.features.findIndex((candidate) => candidate.id === originalPhase.featureId);
2259
+ if (featureIndex < 0)
2260
+ throw new PlanStoreError(`Parent feature ${originalPhase.featureId} not found for phase ${phaseId}.`);
2261
+ const timestamp = nowISO();
2262
+ const applied = applyHandoffContextSync(originalPhase, originalFeatures.features[featureIndex], input, timestamp);
2263
+ const nextFeatures = structuredClone(originalFeatures);
2264
+ nextFeatures.features[featureIndex] = applied.feature;
2265
+ try {
2266
+ await this.saveFeatures(nextFeatures);
2267
+ await this.savePhase(applied.phase);
2268
+ }
2269
+ catch (error) {
2270
+ const rollbackErrors = [];
2271
+ await this.saveFeatures(originalFeatures).catch((rollbackError) => rollbackErrors.push(rollbackError));
2272
+ await this.savePhase(originalPhase).catch((rollbackError) => rollbackErrors.push(rollbackError));
2273
+ if (rollbackErrors.length > 0) {
2274
+ throw new AggregateError([error, ...rollbackErrors], "Handoff refresh failed and rollback was incomplete.");
2275
+ }
2276
+ throw error;
2277
+ }
2278
+ const phase = await this.loadPhase(phaseId);
2279
+ const feature = (await this.loadFeatures()).features.find((candidate) => candidate.id === originalPhase.featureId);
2280
+ return { phase, feature, updatedTaskIds: applied.updatedTaskIds, handoffUpdatedAt: phase.handoffUpdatedAt };
2281
+ });
2282
+ }
2141
2283
  /** Set the handoff text for a phase + stamp handoffUpdatedAt. A completed or
2142
2284
  * canceled phase cannot receive a new operational handoff. Replacing an
2143
2285
  * existing handoff archives the previous content as `superseded` first. */
@@ -1,13 +1,3 @@
1
- /**
2
- * Canonical planner extension rules — the agent-behavior contract that applies
3
- * to EVERY project using the Agent Plan extension (Pi, MCP / Claude Code / Codex,
4
- * future harnesses). These are STATIC: no timestamps, no dynamic content, so the
5
- * same text seeds every .planner/ and never diverges across worktrees or
6
- * branches (no conflict from date/timestamp changes).
7
- *
8
- * AGENTS.md governs ONLY the development of the agent-plan extension and must
9
- * not duplicate these rules.
10
- */
11
1
  export declare const PLANNER_EXTENSION_RULES: string[];
12
2
  export interface ExtensionRulesFile {
13
3
  extensionRules: string[];
@@ -15,7 +5,9 @@ export interface ExtensionRulesFile {
15
5
  /**
16
6
  * Load the effective extension rules for a planner root. Returns the project's
17
7
  * own .planner/rules.json (static, user-overridable) when present and non-empty,
18
- * otherwise the canonical code set. Never returns timestamps or dynamic data.
8
+ * otherwise the canonical code set. Exact legacy canonical read-protocol rules
9
+ * are upgraded in memory without rewriting the project file; unrelated project
10
+ * overrides remain untouched. Never returns timestamps or dynamic data.
19
11
  */
20
12
  export declare function loadExtensionRules(plannerRoot: string): Promise<string[]>;
21
13
  //# sourceMappingURL=planner-rules.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"planner-rules.d.ts","sourceRoot":"","sources":["../src/planner-rules.ts"],"names":[],"mappings":"AAGA;;;;;;;;;GASG;AACH,eAAO,MAAM,uBAAuB,EAAE,MAAM,EA2B3C,CAAC;AAEF,MAAM,WAAW,kBAAkB;IACjC,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAW/E"}
1
+ {"version":3,"file":"planner-rules.d.ts","sourceRoot":"","sources":["../src/planner-rules.ts"],"names":[],"mappings":"AAmBA,eAAO,MAAM,uBAAuB,EAAE,MAAM,EA2B3C,CAAC;AAEF,MAAM,WAAW,kBAAkB;IACjC,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAUD;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAW/E"}
@@ -10,11 +10,15 @@ import { join } from "node:path";
10
10
  * AGENTS.md governs ONLY the development of the agent-plan extension and must
11
11
  * not duplicate these rules.
12
12
  */
13
+ const DETAIL_WRITING_RULE = "Write relevant points (decisions, constraints, current state, file:line refs, edge cases) into the task/phase/feature description or notes as soon as they emerge. For starting, resuming, or switching, call the lifecycle tool first so valid session attestations can be reused. If it denies the operation, perform only the missing or stale full reads listed in nextActions, in that exact order, then retry; read linked requirements explicitly only when requested. Cite entities with composite IDs, not bare UUIDs.";
14
+ const EXPECTED_OPERATIONAL_RULE = "When you begin work, task_start and task_switch enforce session-scoped context reads and return precise missing/stale read actions when needed. Read any relevant phase handoff as additional context, then update the planner before and after significant changes. If you change an architectural decision, document it explicitly.";
15
+ const LEGACY_DETAIL_WRITING_RULE = "Write relevant points (decisions, constraints, current state, file:line refs, edge cases) into the task/phase/feature description or notes as soon as they emerge. Before starting, resuming, or switching to a task, read task_get(full=true), then its parent phase_get(full=true), then its parent feature_get(full=true), in that exact order; read linked requirements explicitly when present. Cite entities with composite IDs, not bare UUIDs.";
16
+ const LEGACY_EXPECTED_OPERATIONAL_RULE = "When you begin work, task_start and task_switch enforce the required ordered full reads. Read any relevant phase handoff as additional context, then update the planner before and after significant changes. If you change an architectural decision, document it explicitly.";
13
17
  export const PLANNER_EXTENSION_RULES = [
14
18
  // §1 — source of truth
15
19
  "Keep the planner as the single operational source of truth while working: read the relevant planner state before starting; update it when an activity starts, changes state, blocks, or concludes; and record next steps, blockers, and decisions in the relevant planner entities. Never leave work only in the conversation.",
16
20
  // §2 — task lifecycle
17
- "Respect the task lifecycle strictly. Always call task_start before touching code, and task_complete when a deliverable is done. Sync state changes (start/complete/block) to the planner at the exact moment they happen — never batch updates at session end. If the extension reports 'no active task', immediately start the correct task. A task marked in-progress means you are actually working on it; if you stop, close or block it with a motivation in statusLog. Derived feature/phase status is computed from tasks, not stored in JSON.",
21
+ "Respect the task lifecycle strictly. Always call task_start before touching code, and task_complete with durable evidence of shipped work, verification (including partial verification), remaining/unverified work, files, and decisions when a deliverable is done. Never enter in-progress or done through task_update. Sync state changes (start/complete/block) to the planner at the exact moment they happen — never batch updates at session end. If task_start is denied, the task remains planned: satisfy the stated read prerequisites and retry, and never claim work started without an explicit successful start result. A task marked in-progress means you are actually working on it; if you stop, close or block it with a motivation in statusLog. Derived feature/phase status is computed from tasks, not stored in JSON.",
18
22
  // §3 — markdown not source of truth
19
23
  "Do not treat markdown as the source of truth for the plan. The plan's primary source is structured data in .planner/; markdown is a generated, human/agent-readable view.",
20
24
  // §5 — plan location
@@ -28,27 +32,38 @@ export const PLANNER_EXTENSION_RULES = [
28
32
  // §10 — references
29
33
  "Reference entities with human, unique, composite IDs — Feature 'F001 - Name', Phase 'P001(F001) - Title', Task 'T003 - Number'. Short forms P003/T007 and the 5-char global shortId (e.g. UUXD1) are also valid. Never reference raw UUIDs. To locate an entity, use the compact list tools (feature_list/phase_list/task_list), not by reading .planner/*.json files.",
30
34
  // §12 — handoff
31
- "Handoff is per-phase (phase.handoff), not a file. Write it only on explicit user request; on resume, read it then clear it before starting work. A pending handoff never blocks task_start. Do not leave a handoff stale after processing it.",
35
+ "Handoff is per-phase (phase.handoff), not a file. Write it only on explicit user request and only after the exact feature+phase target is confirmed. Run handoff_prepare for that phase, reconcile all still-relevant existing content into one active handoff, and synchronize durable task/phase/feature context in the same handoff_write operation. A pending handoff never blocks task_start and is archived only when the phase completes or the user explicitly clears it; refreshing it must not create superseded copies.",
32
36
  // §12 — operational hygiene
33
37
  "Operational hygiene: start the task (task_start) before thinking about implementation; complete it (task_complete) as part of delivering the deliverable, not after; motivate every block so a third party can understand the impediment.",
34
- // Avvio del planner
38
+ // Planner startup
35
39
  "The planner and Web UI never start automatically. Do not start the Web UI or show its URL unless the user runs load/recap/web-status. The Web UI URL appears only in the recap after load, or on explicit web status.",
36
- // Regola dettagli
37
- "Write relevant points (decisions, constraints, current state, file:line refs, edge cases) into the task/phase/feature description or notes as soon as they emerge. Before starting, resuming, or switching to a task, read task_get(full=true), then its parent phase_get(full=true), then its parent feature_get(full=true), in that exact order; read linked requirements explicitly when present. Cite entities with composite IDs, not bare UUIDs.",
40
+ // Detail-writing rule
41
+ DETAIL_WRITING_RULE,
38
42
  // Expected operational behavior
39
- "When you begin work, task_start and task_switch enforce the required ordered full reads. Read any relevant phase handoff as additional context, then update the planner before and after significant changes. If you change an architectural decision, document it explicitly.",
43
+ EXPECTED_OPERATIONAL_RULE,
40
44
  ];
45
+ function normalizeLegacyRules(rules) {
46
+ return rules.map((rule) => {
47
+ if (rule === LEGACY_DETAIL_WRITING_RULE)
48
+ return DETAIL_WRITING_RULE;
49
+ if (rule === LEGACY_EXPECTED_OPERATIONAL_RULE)
50
+ return EXPECTED_OPERATIONAL_RULE;
51
+ return rule;
52
+ });
53
+ }
41
54
  /**
42
55
  * Load the effective extension rules for a planner root. Returns the project's
43
56
  * own .planner/rules.json (static, user-overridable) when present and non-empty,
44
- * otherwise the canonical code set. Never returns timestamps or dynamic data.
57
+ * otherwise the canonical code set. Exact legacy canonical read-protocol rules
58
+ * are upgraded in memory without rewriting the project file; unrelated project
59
+ * overrides remain untouched. Never returns timestamps or dynamic data.
45
60
  */
46
61
  export async function loadExtensionRules(plannerRoot) {
47
62
  try {
48
63
  const raw = await readFile(join(plannerRoot, "rules.json"), "utf8");
49
64
  const parsed = JSON.parse(raw);
50
65
  if (Array.isArray(parsed.extensionRules) && parsed.extensionRules.length > 0) {
51
- return parsed.extensionRules.filter((r) => typeof r === "string" && r.length > 0);
66
+ return normalizeLegacyRules(parsed.extensionRules.filter((r) => typeof r === "string" && r.length > 0));
52
67
  }
53
68
  }
54
69
  catch {