@agent-plan/core 0.2.19-next.2 → 0.2.19-next.4

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.
@@ -63,7 +63,6 @@ export declare class PlanStore {
63
63
  private codebasePath;
64
64
  private resumePath;
65
65
  private activityPath;
66
- private handoffPath;
67
66
  init(projectName: string): Promise<void>;
68
67
  exists(): Promise<boolean>;
69
68
  loadManifest(): Promise<Manifest>;
@@ -90,14 +89,6 @@ export declare class PlanStore {
90
89
  /** True when a guard bypass is currently active (not expired). */
91
90
  isGuardBypassed(): Promise<boolean>;
92
91
  loadActivityLog(): Promise<ActivityLog>;
93
- handoffExists(): Promise<boolean>;
94
- loadHandoff(): Promise<{
95
- content: string;
96
- createdAt: string;
97
- updatedAt: string;
98
- } | null>;
99
- saveHandoff(content: string): Promise<void>;
100
- deleteHandoff(): Promise<void>;
101
92
  appendActivity(type: string, ref: string, summary: string): Promise<ActivityEntry>;
102
93
  /** Derive an up-to-date resume focus from the current workspace state. */
103
94
  refreshResume(notes?: string, lastSessionSummary?: string): Promise<ResumeFocus>;
@@ -188,9 +179,32 @@ export declare class PlanStore {
188
179
  /** Set the handoff text for a phase + stamp handoffUpdatedAt. Atomic per-file
189
180
  * update via updatePhase (so the web UI refreshes via maybeAutoSync). */
190
181
  setPhaseHandoff(phaseId: string, text: string): Promise<void>;
191
- /** Clear the handoff text for a phase (handoff=""). handoffUpdatedAt is left
192
- * unchanged as an audit trail (when a handoff last existed). */
193
- clearPhaseHandoff(phaseId: string): Promise<void>;
182
+ /** Directory where cleared handoff content is archived as .md files
183
+ * (gitignored). Keeps the phase JSON lean while making past handoffs
184
+ * recoverable + human-readable. */
185
+ private handoffArchiveDir;
186
+ /** Mark the phase handoff as read/acknowledged on recap (sets handoffReadAt).
187
+ * Does NOT clear the handoff — content is kept until a task starts or the
188
+ * phase completes, so a restart between read and resume does not lose it. */
189
+ markHandoffRead(phaseId: string): Promise<void>;
190
+ /** One-time import of a legacy .planner/HANDOFF.md file (file-based handoff
191
+ * from before F004) into the entity-scoped phase.handoff. Idempotent: if the
192
+ * file is absent or empty, no-op. If it exists + non-empty + the target phase
193
+ * has no handoff, writes the content onto the current in-progress phase (or
194
+ * the first phase if none in-progress) with an "imported" handoffHistory entry,
195
+ * then renames the file to HANDOFF.md.bak so it won't re-import. If the target
196
+ * already has a handoff, the entity-scoped one wins and the file is just .bak'd. */
197
+ importLegacyHandoffFile(): Promise<{
198
+ imported: boolean;
199
+ phaseRef?: string;
200
+ }>;
201
+ /** Clear the handoff for a phase, archiving its content first. The handoff
202
+ * markdown is written to .planner/handoff-archive/<phaseId>-<ISO>.md and a
203
+ * metadata entry { file, clearedAt, reason } is prepended to handoffHistory
204
+ * (capped at 5; oldest file is deleted when trimmed). handoffUpdatedAt is
205
+ * left unchanged as an audit trail. If the handoff is empty, this is a no-op.
206
+ * reason: "task-started" | "phase-done" | "manual" | "superseded" | "imported". */
207
+ clearPhaseHandoff(phaseId: string, reason?: string): Promise<void>;
194
208
  /** List all phases that have a non-empty handoff, newest first, with a
195
209
  * human-readable composite ref (P00x or P00x(F00x)) and a first-line excerpt. */
196
210
  listHandoffs(): Promise<PhaseHandoffSummary[]>;
@@ -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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"}
@@ -1,4 +1,4 @@
1
- import { access, copyFile, mkdir, readdir, readFile, rename, stat, unlink, writeFile } from "node:fs/promises";
1
+ import { access, copyFile, mkdir, readdir, readFile, rename, unlink, writeFile } from "node:fs/promises";
2
2
  import { join } from "node:path";
3
3
  import { CodebaseProfileSchema, FeatureSchema, FeaturesDocumentSchema, ManifestSchema, PhaseSchema, ProjectSchema, RequirementsDocumentSchema, ResumeFocusSchema, ActivityLogSchema, } from "./schema.js";
4
4
  import { createFeatureId, createPhaseId, createRequirementId, createShortId, createTaskId, formatPhaseRef, isLegacyPhaseId } from "./naming.js";
@@ -338,7 +338,7 @@ export class PlanStore {
338
338
  };
339
339
  }
340
340
  async ensureStructureOrdering() {
341
- return this.runAsBatch(async () => {
341
+ const result = await this.runAsBatch(async () => {
342
342
  const featuresDoc = await this.loadFeatures();
343
343
  const phases = await this.loadAllPhases();
344
344
  const normalized = this.normalizeStructureSnapshot(featuresDoc, phases);
@@ -350,6 +350,10 @@ export class PlanStore {
350
350
  }
351
351
  return { changed: true };
352
352
  });
353
+ // One-time import of a legacy file-based HANDOFF.md (pre-F004) into the
354
+ // entity-scoped phase.handoff. Idempotent — renames the file to .bak.
355
+ await this.importLegacyHandoffFile().catch(() => { });
356
+ return result;
353
357
  }
354
358
  // ── Path helpers ─────────────────────────────────────────────────────
355
359
  manifestPath() {
@@ -411,9 +415,6 @@ export class PlanStore {
411
415
  activityPath() {
412
416
  return join(this.root, "activity.json");
413
417
  }
414
- handoffPath() {
415
- return join(this.root, "HANDOFF.md");
416
- }
417
418
  // ── Init ─────────────────────────────────────────────────────────────
418
419
  async init(projectName) {
419
420
  if (await this.exists()) {
@@ -460,6 +461,7 @@ export class PlanStore {
460
461
  currentPhaseId: "",
461
462
  inProgressTaskIds: [],
462
463
  nextSteps: ["Run /planner project discuss to bootstrap discovery"],
464
+ nextStepsUpdatedAt: nowISO(),
463
465
  blockers: [],
464
466
  notes: "Project initialized. Awaiting discovery.",
465
467
  lastSessionSummary: "",
@@ -495,6 +497,7 @@ export class PlanStore {
495
497
  "resume.json",
496
498
  "resume.*.json",
497
499
  "generated/",
500
+ "handoff-archive/",
498
501
  "",
499
502
  ].join("\n"), "utf-8");
500
503
  }
@@ -589,7 +592,18 @@ export class PlanStore {
589
592
  }
590
593
  }
591
594
  async saveResume(resume) {
592
- const parsed = ResumeFocusSchema.parse(resume);
595
+ // Track when `nextSteps` actually change (free-text can go stale; the recap
596
+ // surfaces nextStepsUpdatedAt so staleness is visible). Preserved when
597
+ // refreshResume keeps existing nextSteps; bumped only on a real change.
598
+ const existing = await this.loadResume().catch(() => null);
599
+ const nextStepsChanged = JSON.stringify(existing?.nextSteps ?? []) !== JSON.stringify(resume.nextSteps ?? []);
600
+ const withTs = {
601
+ ...resume,
602
+ nextStepsUpdatedAt: nextStepsChanged
603
+ ? nowISO()
604
+ : (resume.nextStepsUpdatedAt || existing?.nextStepsUpdatedAt || nowISO()),
605
+ };
606
+ const parsed = ResumeFocusSchema.parse(withTs);
593
607
  await atomicWriteJson(this.resumePath(), parsed);
594
608
  await this.touchManifest();
595
609
  }
@@ -605,6 +619,7 @@ export class PlanStore {
605
619
  currentPhaseId: "",
606
620
  inProgressTaskIds: [],
607
621
  nextSteps: [],
622
+ nextStepsUpdatedAt: "",
608
623
  blockers: [],
609
624
  notes: "",
610
625
  lastSessionSummary: "",
@@ -643,44 +658,6 @@ export class PlanStore {
643
658
  return { entries: [] };
644
659
  }
645
660
  }
646
- async handoffExists() {
647
- try {
648
- await access(this.handoffPath());
649
- return true;
650
- }
651
- catch {
652
- return false;
653
- }
654
- }
655
- async loadHandoff() {
656
- try {
657
- const [content, info] = await Promise.all([
658
- readFile(this.handoffPath(), "utf-8"),
659
- stat(this.handoffPath()),
660
- ]);
661
- const createdAt = content.match(/^Created at:\s*(.+)$/m)?.[1]?.trim() ?? info.birthtime.toISOString();
662
- const updatedAt = content.match(/^Updated at:\s*(.+)$/m)?.[1]?.trim() ?? info.mtime.toISOString();
663
- return {
664
- content,
665
- createdAt,
666
- updatedAt,
667
- };
668
- }
669
- catch {
670
- return null;
671
- }
672
- }
673
- async saveHandoff(content) {
674
- await atomicWriteText(this.handoffPath(), content);
675
- await this.touchManifest();
676
- }
677
- async deleteHandoff() {
678
- try {
679
- await unlink(this.handoffPath());
680
- }
681
- catch { }
682
- await this.touchManifest();
683
- }
684
661
  async appendActivity(type, ref, summary) {
685
662
  const log = await this.loadActivityLog();
686
663
  const id = `act-${log.entries.length + 1}-${type}`;
@@ -705,6 +682,7 @@ export class PlanStore {
705
682
  currentPhaseId: inProgressPhases[0]?.id ?? existing?.currentPhaseId ?? "",
706
683
  inProgressTaskIds: inProgressTasks.map((t) => t.id),
707
684
  nextSteps: existing?.nextSteps ?? [],
685
+ nextStepsUpdatedAt: existing?.nextStepsUpdatedAt ?? "",
708
686
  blockers: blockedTasks.map((t) => `${t.id}: ${t.title}`),
709
687
  notes: notes ?? existing?.notes ?? "",
710
688
  lastSessionSummary: lastSessionSummary ?? existing?.lastSessionSummary ?? "",
@@ -1128,7 +1106,7 @@ export class PlanStore {
1128
1106
  const phase = await this.loadPhase(phaseId);
1129
1107
  let cleared = null;
1130
1108
  if (phase.status === "done" && phase.handoff !== "") {
1131
- await this.updatePhase(phaseId, (p) => ({ ...p, handoff: "", handoffUpdatedAt: nowISO() }));
1109
+ await this.clearPhaseHandoff(phaseId, "phase-done");
1132
1110
  const features = await this.loadFeatures();
1133
1111
  const feature = features.features.find((f) => f.id === phase.featureId);
1134
1112
  cleared = formatPhaseRef(phase.number, feature?.number);
@@ -1246,10 +1224,76 @@ export class PlanStore {
1246
1224
  const now = new Date().toISOString();
1247
1225
  await this.updatePhase(phaseId, (phase) => ({ ...phase, handoff: text, handoffUpdatedAt: now }));
1248
1226
  }
1249
- /** Clear the handoff text for a phase (handoff=""). handoffUpdatedAt is left
1250
- * unchanged as an audit trail (when a handoff last existed). */
1251
- async clearPhaseHandoff(phaseId) {
1252
- await this.updatePhase(phaseId, (phase) => ({ ...phase, handoff: "" }));
1227
+ /** Directory where cleared handoff content is archived as .md files
1228
+ * (gitignored). Keeps the phase JSON lean while making past handoffs
1229
+ * recoverable + human-readable. */
1230
+ handoffArchiveDir() {
1231
+ return join(this.root, "handoff-archive");
1232
+ }
1233
+ /** Mark the phase handoff as read/acknowledged on recap (sets handoffReadAt).
1234
+ * Does NOT clear the handoff — content is kept until a task starts or the
1235
+ * phase completes, so a restart between read and resume does not lose it. */
1236
+ async markHandoffRead(phaseId) {
1237
+ await this.updatePhase(phaseId, (phase) => ({ ...phase, handoffReadAt: nowISO() }));
1238
+ }
1239
+ /** One-time import of a legacy .planner/HANDOFF.md file (file-based handoff
1240
+ * from before F004) into the entity-scoped phase.handoff. Idempotent: if the
1241
+ * file is absent or empty, no-op. If it exists + non-empty + the target phase
1242
+ * has no handoff, writes the content onto the current in-progress phase (or
1243
+ * the first phase if none in-progress) with an "imported" handoffHistory entry,
1244
+ * then renames the file to HANDOFF.md.bak so it won't re-import. If the target
1245
+ * already has a handoff, the entity-scoped one wins and the file is just .bak'd. */
1246
+ async importLegacyHandoffFile() {
1247
+ const filePath = join(this.root, "HANDOFF.md");
1248
+ const content = await readFile(filePath, "utf-8").catch(() => null);
1249
+ if (content === null)
1250
+ return { imported: false };
1251
+ if (content.trim() === "") {
1252
+ await rename(filePath, filePath + ".bak").catch(() => { });
1253
+ return { imported: false };
1254
+ }
1255
+ const phases = await this.loadAllPhases();
1256
+ const target = phases.find((p) => p.status === "in-progress") ?? phases[0] ?? null;
1257
+ if (!target)
1258
+ return { imported: false }; // no phases yet — leave file for a later run
1259
+ if ((target.handoff ?? "") === "") {
1260
+ await this.setPhaseHandoff(target.id, content + "\n\n<!-- imported from legacy .planner/HANDOFF.md -->\n");
1261
+ await this.updatePhase(target.id, (p) => ({
1262
+ ...p,
1263
+ handoffHistory: [{ file: "(legacy HANDOFF.md)", clearedAt: nowISO(), reason: "imported" }, ...(p.handoffHistory ?? [])].slice(0, 5),
1264
+ }));
1265
+ }
1266
+ await rename(filePath, filePath + ".bak").catch(() => { });
1267
+ const features = await this.loadFeatures();
1268
+ const feat = features.features.find((f) => f.id === target.featureId);
1269
+ return { imported: true, phaseRef: formatPhaseRef(target.number, feat?.number) };
1270
+ }
1271
+ /** Clear the handoff for a phase, archiving its content first. The handoff
1272
+ * markdown is written to .planner/handoff-archive/<phaseId>-<ISO>.md and a
1273
+ * metadata entry { file, clearedAt, reason } is prepended to handoffHistory
1274
+ * (capped at 5; oldest file is deleted when trimmed). handoffUpdatedAt is
1275
+ * left unchanged as an audit trail. If the handoff is empty, this is a no-op.
1276
+ * reason: "task-started" | "phase-done" | "manual" | "superseded" | "imported". */
1277
+ async clearPhaseHandoff(phaseId, reason = "manual") {
1278
+ const phase = await this.loadPhase(phaseId).catch(() => null);
1279
+ if (!phase || phase.handoff === "")
1280
+ return; // nothing to archive
1281
+ const clearedAt = nowISO();
1282
+ const safeTs = clearedAt.replace(/[:.]/g, "-");
1283
+ const archiveDir = this.handoffArchiveDir();
1284
+ await mkdir(archiveDir, { recursive: true }).catch(() => { });
1285
+ const fileName = `${phaseId}-${safeTs}.md`;
1286
+ const filePath = join(archiveDir, fileName);
1287
+ await atomicWriteText(filePath, phase.handoff);
1288
+ const entry = { file: `handoff-archive/${fileName}`, clearedAt, reason };
1289
+ // Cap history at 5: prepend new entry, drop oldest (and delete its file).
1290
+ const trimmed = [entry, ...(phase.handoffHistory ?? [])].slice(0, 5);
1291
+ const dropped = (phase.handoffHistory ?? []).slice(4); // entries beyond index 4 after prepend
1292
+ for (const d of dropped) {
1293
+ if (d?.file)
1294
+ await unlink(join(this.root, d.file)).catch(() => { });
1295
+ }
1296
+ await this.updatePhase(phaseId, (p) => ({ ...p, handoff: "", handoffHistory: trimmed }));
1253
1297
  }
1254
1298
  /** List all phases that have a non-empty handoff, newest first, with a
1255
1299
  * human-readable composite ref (P00x or P00x(F00x)) and a first-line excerpt. */
@@ -1 +1 @@
1
- {"version":3,"file":"recap.d.ts","sourceRoot":"","sources":["../src/recap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAGjD;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3B;AAED,yEAAyE;AACzE,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,KAAK,CAAC;AAExC,MAAM,WAAW,YAAY;IAC3B,OAAO,CAAC,EAAE,YAAY,CAAC;CACxB;AAKD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,GAAG,GAAE,YAAiB,EAAE,IAAI,GAAE,YAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,CA+GhH"}
1
+ {"version":3,"file":"recap.d.ts","sourceRoot":"","sources":["../src/recap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAGjD;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3B;AAED,yEAAyE;AACzE,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,KAAK,CAAC;AAExC,MAAM,WAAW,YAAY;IAC3B,OAAO,CAAC,EAAE,YAAY,CAAC;CACxB;AAKD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,GAAG,GAAE,YAAiB,EAAE,IAAI,GAAE,YAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,CA8HhH"}
package/dist/recap.js CHANGED
@@ -49,7 +49,6 @@ export async function buildRecap(st, web = {}, opts = {}) {
49
49
  const featureAddCmd = cmd("/planner feature add", "planner-feature-add");
50
50
  const phaseAddCmd = cmd("/planner phase add", "planner-phase-add");
51
51
  const handoffShowCmd = cmd("/planner handoff show", "planner-handoff-show");
52
- const handoffClearCmd = cmd("/planner handoff clear", "planner-handoff-clear");
53
52
  const lines = [];
54
53
  lines.push(italian ? "## Ripresa planner" : "## Planner recap");
55
54
  const name = plan.project.name || "(unnamed project)";
@@ -71,18 +70,33 @@ export async function buildRecap(st, web = {}, opts = {}) {
71
70
  else {
72
71
  lines.push(`${italian ? "Focus corrente" : "Current focus"}: ${italian ? "nessun task attivo — rivedi il piano e scegli il prossimo task concreto" : "no active task — review the plan and pick the next concrete task"}`);
73
72
  }
74
- // Next step: only surface resume.nextSteps when the plan is NOT complete —
75
- // otherwise stale init-time steps (e.g. "bootstrap discovery") leak through
76
- // and contradict an all-done plan.
77
- if (!planComplete && resume?.nextSteps?.length) {
73
+ // Next step: the phase handoff (phase.handoff) is the authoritative,
74
+ // actively-managed resume context. When a handoff is pending, point to it
75
+ // instead of surfacing potentially-stale resume.json nextSteps. When no
76
+ // handoff exists, fall back to resume.nextSteps but mark them as possibly
77
+ // stale (free-text that refreshResume never touches, so they can drift).
78
+ if (handoffs.length > 0) {
79
+ lines.push(italian
80
+ ? `Prossimo step: leggi l'handoff di fase pendente sotto (fonte autorevole, gestita attivamente). I nextSteps legacy di resume.json sono soppressi perché possono essere stale.`
81
+ : `Next step: read the pending phase handoff below (authoritative, actively maintained). Legacy resume.json nextSteps are suppressed because they may be stale.`);
82
+ }
83
+ else if (!planComplete && resume?.nextSteps?.length) {
78
84
  lines.push(`${italian ? "Prossimo step" : "Next step"}: ${resume.nextSteps[0]}`);
85
+ const staleNote = resume.nextStepsUpdatedAt
86
+ ? (italian
87
+ ? `⚠️ nextSteps free-text da resume.json, ultimo aggiornamento ${resume.nextStepsUpdatedAt} — può essere stale; verifica contro lo stato attuale prima di agire.`
88
+ : `⚠️ nextSteps are free-text from resume.json, last updated ${resume.nextStepsUpdatedAt} — may be stale; verify against current state before acting.`)
89
+ : (italian
90
+ ? `⚠️ nextSteps free-text da resume.json — può essere stale; verifica contro lo stato attuale prima di agire.`
91
+ : `⚠️ nextSteps are free-text from resume.json — may be stale; verify against current state before acting.`);
92
+ lines.push(staleNote);
79
93
  }
80
94
  if (handoffs.length > 0) {
81
95
  lines.push("", italian ? `## Handoff di fase pendenti (${handoffs.length})` : `## Pending phase handoffs (${handoffs.length})`);
82
96
  handoffs.forEach((h, i) => lines.push(`[${i + 1}] ${h.compositeRef} — ${h.updatedAt} — "${h.firstLine}"`));
83
97
  lines.push("", italian
84
- ? `→ Leggi quello pertinente con ${handoffShowCmd} <ref> (valida contro lo stato attuale), poi ${handoffClearCmd} <ref> una volta consumato.`
85
- : `→ Read the relevant one with ${handoffShowCmd} <ref> (validate against current state), then call ${handoffClearCmd} <ref> once consumed (delete-on-resume).`);
98
+ ? `→ Leggi quello pertinente con ${handoffShowCmd} <ref> (valida contro lo stato attuale). L'handoff è MANTENUTO finché un task della fase non parte (auto-archiviato) o la fase non si conclude — non serve cancellarlo a mano.`
99
+ : `→ Read the relevant one with ${handoffShowCmd} <ref> (validate against current state). It is KEPT until a task in that phase starts (then auto-archived) or the phase completes — no need to clear it manually.`);
86
100
  }
87
101
  else if (planComplete) {
88
102
  lines.push("", italian
package/dist/schema.d.ts CHANGED
@@ -133,6 +133,10 @@ export declare const ResumeFocusSchema: z.ZodObject<{
133
133
  currentPhaseId: z.ZodDefault<z.ZodString>;
134
134
  inProgressTaskIds: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
135
135
  nextSteps: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
136
+ /** When `nextSteps` last changed (free-text can go stale; the recap surfaces
137
+ * this so staleness is visible). Preserved across refreshResume (which keeps
138
+ * existing nextSteps); bumped only when saveResume receives new nextSteps. */
139
+ nextStepsUpdatedAt: z.ZodDefault<z.ZodString>;
136
140
  blockers: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
137
141
  notes: z.ZodDefault<z.ZodString>;
138
142
  lastSessionSummary: z.ZodDefault<z.ZodString>;
@@ -142,6 +146,7 @@ export declare const ResumeFocusSchema: z.ZodObject<{
142
146
  currentPhaseId: string;
143
147
  inProgressTaskIds: string[];
144
148
  nextSteps: string[];
149
+ nextStepsUpdatedAt: string;
145
150
  blockers: string[];
146
151
  notes: string;
147
152
  lastSessionSummary: string;
@@ -151,6 +156,7 @@ export declare const ResumeFocusSchema: z.ZodObject<{
151
156
  currentPhaseId?: string | undefined;
152
157
  inProgressTaskIds?: string[] | undefined;
153
158
  nextSteps?: string[] | undefined;
159
+ nextStepsUpdatedAt?: string | undefined;
154
160
  blockers?: string[] | undefined;
155
161
  notes?: string | undefined;
156
162
  lastSessionSummary?: string | undefined;
@@ -719,6 +725,21 @@ export declare const TaskSchema: z.ZodEffects<z.ZodObject<{
719
725
  startedAt?: string | undefined;
720
726
  completedAt?: string | undefined;
721
727
  }>;
728
+ export declare const HandoffHistoryEntrySchema: z.ZodObject<{
729
+ /** Relative path under .planner/handoff-archive/ (e.g. <phaseId>-<ISO>.md). */
730
+ file: z.ZodDefault<z.ZodString>;
731
+ clearedAt: z.ZodString;
732
+ /** Why the handoff was cleared: "task-started" | "phase-done" | "manual" | "superseded" | "imported". */
733
+ reason: z.ZodDefault<z.ZodString>;
734
+ }, "strip", z.ZodTypeAny, {
735
+ file: string;
736
+ clearedAt: string;
737
+ reason: string;
738
+ }, {
739
+ clearedAt: string;
740
+ file?: string | undefined;
741
+ reason?: string | undefined;
742
+ }>;
722
743
  export declare const PhaseSchema: z.ZodObject<{
723
744
  id: z.ZodString;
724
745
  featureId: z.ZodOptional<z.ZodString>;
@@ -1049,6 +1070,30 @@ export declare const PhaseSchema: z.ZodObject<{
1049
1070
  updatedAt: z.ZodString;
1050
1071
  handoff: z.ZodDefault<z.ZodString>;
1051
1072
  handoffUpdatedAt: z.ZodDefault<z.ZodString>;
1073
+ /** When the handoff was last read/acknowledged on recap (ISO). Non-empty means
1074
+ * the agent has seen it; the recap won't re-prompt every turn. The handoff
1075
+ * content is KEPT until a task in the phase starts (auto-clear) or the phase
1076
+ * completes — so a restart between read and resume does not lose context. */
1077
+ handoffReadAt: z.ZodDefault<z.ZodString>;
1078
+ /** Metadata for recently-cleared handoffs (newest-first, capped at 5). The
1079
+ * full content lives as .md files in .planner/handoff-archive/ (gitignored);
1080
+ * this array only holds the pointer + clear reason + timestamp, so the phase
1081
+ * JSON stays lean and the archive is recoverable. */
1082
+ handoffHistory: z.ZodDefault<z.ZodArray<z.ZodObject<{
1083
+ /** Relative path under .planner/handoff-archive/ (e.g. <phaseId>-<ISO>.md). */
1084
+ file: z.ZodDefault<z.ZodString>;
1085
+ clearedAt: z.ZodString;
1086
+ /** Why the handoff was cleared: "task-started" | "phase-done" | "manual" | "superseded" | "imported". */
1087
+ reason: z.ZodDefault<z.ZodString>;
1088
+ }, "strip", z.ZodTypeAny, {
1089
+ file: string;
1090
+ clearedAt: string;
1091
+ reason: string;
1092
+ }, {
1093
+ clearedAt: string;
1094
+ file?: string | undefined;
1095
+ reason?: string | undefined;
1096
+ }>, "many">>;
1052
1097
  }, "strip", z.ZodTypeAny, {
1053
1098
  number: number;
1054
1099
  dependencies: string[];
@@ -1130,6 +1175,12 @@ export declare const PhaseSchema: z.ZodObject<{
1130
1175
  }[];
1131
1176
  handoff: string;
1132
1177
  handoffUpdatedAt: string;
1178
+ handoffReadAt: string;
1179
+ handoffHistory: {
1180
+ file: string;
1181
+ clearedAt: string;
1182
+ reason: string;
1183
+ }[];
1133
1184
  featureId?: string | undefined;
1134
1185
  }, {
1135
1186
  number: number;
@@ -1213,6 +1264,12 @@ export declare const PhaseSchema: z.ZodObject<{
1213
1264
  }[] | undefined;
1214
1265
  handoff?: string | undefined;
1215
1266
  handoffUpdatedAt?: string | undefined;
1267
+ handoffReadAt?: string | undefined;
1268
+ handoffHistory?: {
1269
+ clearedAt: string;
1270
+ file?: string | undefined;
1271
+ reason?: string | undefined;
1272
+ }[] | undefined;
1216
1273
  }>;
1217
1274
  export declare const FeatureSchema: z.ZodObject<{
1218
1275
  id: z.ZodString;
@@ -2347,6 +2404,30 @@ export declare const PlanWorkspaceSchema: z.ZodObject<{
2347
2404
  updatedAt: z.ZodString;
2348
2405
  handoff: z.ZodDefault<z.ZodString>;
2349
2406
  handoffUpdatedAt: z.ZodDefault<z.ZodString>;
2407
+ /** When the handoff was last read/acknowledged on recap (ISO). Non-empty means
2408
+ * the agent has seen it; the recap won't re-prompt every turn. The handoff
2409
+ * content is KEPT until a task in the phase starts (auto-clear) or the phase
2410
+ * completes — so a restart between read and resume does not lose context. */
2411
+ handoffReadAt: z.ZodDefault<z.ZodString>;
2412
+ /** Metadata for recently-cleared handoffs (newest-first, capped at 5). The
2413
+ * full content lives as .md files in .planner/handoff-archive/ (gitignored);
2414
+ * this array only holds the pointer + clear reason + timestamp, so the phase
2415
+ * JSON stays lean and the archive is recoverable. */
2416
+ handoffHistory: z.ZodDefault<z.ZodArray<z.ZodObject<{
2417
+ /** Relative path under .planner/handoff-archive/ (e.g. <phaseId>-<ISO>.md). */
2418
+ file: z.ZodDefault<z.ZodString>;
2419
+ clearedAt: z.ZodString;
2420
+ /** Why the handoff was cleared: "task-started" | "phase-done" | "manual" | "superseded" | "imported". */
2421
+ reason: z.ZodDefault<z.ZodString>;
2422
+ }, "strip", z.ZodTypeAny, {
2423
+ file: string;
2424
+ clearedAt: string;
2425
+ reason: string;
2426
+ }, {
2427
+ clearedAt: string;
2428
+ file?: string | undefined;
2429
+ reason?: string | undefined;
2430
+ }>, "many">>;
2350
2431
  }, "strip", z.ZodTypeAny, {
2351
2432
  number: number;
2352
2433
  dependencies: string[];
@@ -2428,6 +2509,12 @@ export declare const PlanWorkspaceSchema: z.ZodObject<{
2428
2509
  }[];
2429
2510
  handoff: string;
2430
2511
  handoffUpdatedAt: string;
2512
+ handoffReadAt: string;
2513
+ handoffHistory: {
2514
+ file: string;
2515
+ clearedAt: string;
2516
+ reason: string;
2517
+ }[];
2431
2518
  featureId?: string | undefined;
2432
2519
  }, {
2433
2520
  number: number;
@@ -2511,6 +2598,12 @@ export declare const PlanWorkspaceSchema: z.ZodObject<{
2511
2598
  }[] | undefined;
2512
2599
  handoff?: string | undefined;
2513
2600
  handoffUpdatedAt?: string | undefined;
2601
+ handoffReadAt?: string | undefined;
2602
+ handoffHistory?: {
2603
+ clearedAt: string;
2604
+ file?: string | undefined;
2605
+ reason?: string | undefined;
2606
+ }[] | undefined;
2514
2607
  }>, "many">;
2515
2608
  }, "strip", z.ZodTypeAny, {
2516
2609
  features: {
@@ -2676,6 +2769,12 @@ export declare const PlanWorkspaceSchema: z.ZodObject<{
2676
2769
  }[];
2677
2770
  handoff: string;
2678
2771
  handoffUpdatedAt: string;
2772
+ handoffReadAt: string;
2773
+ handoffHistory: {
2774
+ file: string;
2775
+ clearedAt: string;
2776
+ reason: string;
2777
+ }[];
2679
2778
  featureId?: string | undefined;
2680
2779
  }[];
2681
2780
  }, {
@@ -2843,6 +2942,12 @@ export declare const PlanWorkspaceSchema: z.ZodObject<{
2843
2942
  }[] | undefined;
2844
2943
  handoff?: string | undefined;
2845
2944
  handoffUpdatedAt?: string | undefined;
2945
+ handoffReadAt?: string | undefined;
2946
+ handoffHistory?: {
2947
+ clearedAt: string;
2948
+ file?: string | undefined;
2949
+ reason?: string | undefined;
2950
+ }[] | undefined;
2846
2951
  }[];
2847
2952
  }>;
2848
2953
  export type Timestamp = z.infer<typeof TimestampSchema>;
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
package/dist/schema.js CHANGED
@@ -37,6 +37,10 @@ export const ResumeFocusSchema = z.object({
37
37
  currentPhaseId: z.string().default(""),
38
38
  inProgressTaskIds: z.array(z.string().min(1)).default([]),
39
39
  nextSteps: z.array(z.string().min(1)).default([]),
40
+ /** When `nextSteps` last changed (free-text can go stale; the recap surfaces
41
+ * this so staleness is visible). Preserved across refreshResume (which keeps
42
+ * existing nextSteps); bumped only when saveResume receives new nextSteps. */
43
+ nextStepsUpdatedAt: z.string().default(""),
40
44
  blockers: z.array(z.string().min(1)).default([]),
41
45
  notes: z.string().default(""),
42
46
  lastSessionSummary: z.string().default(""),
@@ -163,6 +167,13 @@ export const TaskSchema = z.object({
163
167
  : { ...item, id: item.id || createChecklistItemId(task.id, index + 1, item.title), title: item.title.trim(), checked: item.checked ?? false })
164
168
  .filter((item) => item.title.length > 0),
165
169
  }));
170
+ export const HandoffHistoryEntrySchema = z.object({
171
+ /** Relative path under .planner/handoff-archive/ (e.g. <phaseId>-<ISO>.md). */
172
+ file: z.string().default(""),
173
+ clearedAt: TimestampSchema,
174
+ /** Why the handoff was cleared: "task-started" | "phase-done" | "manual" | "superseded" | "imported". */
175
+ reason: z.string().default(""),
176
+ });
166
177
  export const PhaseSchema = z.object({
167
178
  id: z.string(),
168
179
  featureId: z.string().optional(),
@@ -195,6 +206,16 @@ export const PhaseSchema = z.object({
195
206
  updatedAt: TimestampSchema,
196
207
  handoff: z.string().default(""),
197
208
  handoffUpdatedAt: z.string().default(""),
209
+ /** When the handoff was last read/acknowledged on recap (ISO). Non-empty means
210
+ * the agent has seen it; the recap won't re-prompt every turn. The handoff
211
+ * content is KEPT until a task in the phase starts (auto-clear) or the phase
212
+ * completes — so a restart between read and resume does not lose context. */
213
+ handoffReadAt: z.string().default(""),
214
+ /** Metadata for recently-cleared handoffs (newest-first, capped at 5). The
215
+ * full content lives as .md files in .planner/handoff-archive/ (gitignored);
216
+ * this array only holds the pointer + clear reason + timestamp, so the phase
217
+ * JSON stays lean and the archive is recoverable. */
218
+ handoffHistory: z.array(HandoffHistoryEntrySchema).default([]),
198
219
  });
199
220
  export const FeatureSchema = z.object({
200
221
  id: z.string(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-plan/core",
3
- "version": "0.2.19-next.2",
3
+ "version": "0.2.19-next.4",
4
4
  "private": false,
5
5
  "description": "Harness-agnostic core for Agent Plan: schemas, persistence, ordering, status rollups, and markdown rendering.",
6
6
  "license": "MIT",