@agent-plan/core 0.2.19 → 0.2.21

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.
@@ -14,15 +14,15 @@
14
14
  *
15
15
  * These are NEVER persisted: they are computed on demand from children's
16
16
  * canonical workflow statuses. The canonical workflow model
17
- * (`planned | in-progress | waiting | blocked | deferred | done | canceled |
18
- * rejected`) is unchanged.
17
+ * (`planned | in-progress | paused | waiting | blocked | deferred | done |
18
+ * canceled | rejected`) includes paused leaf work without implying active execution.
19
19
  */
20
20
  import type { TaskStatus, PhaseStatus } from "./schema.js";
21
21
  /**
22
22
  * Canonical workflow status values used by tasks, phases, and features.
23
23
  * Mirrors the union of TaskStatus and PhaseStatus used in the planner data.
24
24
  */
25
- export type WorkflowStatus = "planned" | "in-progress" | "waiting" | "blocked" | "deferred" | "done" | "canceled" | "rejected";
25
+ export type WorkflowStatus = "planned" | "in-progress" | "paused" | "waiting" | "blocked" | "deferred" | "done" | "canceled" | "rejected";
26
26
  /**
27
27
  * Display status adds parent-only presentation states on top of workflow
28
28
  * statuses. Only parent entities (feature, phase) use the full union; leaf
@@ -33,6 +33,7 @@ export type DisplayStatus = WorkflowStatus | "started" | "closed";
33
33
  export interface StatusBreakdown {
34
34
  planned: number;
35
35
  inProgress: number;
36
+ paused: number;
36
37
  waiting: number;
37
38
  blocked: number;
38
39
  deferred: number;
@@ -67,6 +68,7 @@ export declare function countBreakdown(statuses: readonly WorkflowStatus[]): Sta
67
68
  * - all `rejected` → `rejected`
68
69
  * - otherwise → `closed` (mixed terminal outcomes)
69
70
  * 3. Compute `unfinished = meaningful ∩ OPEN`.
71
+ * - homogeneous `paused` → `paused`
70
72
  * - homogeneous `waiting` → `waiting`
71
73
  * - homogeneous `blocked` → `blocked`
72
74
  * - homogeneous `deferred` → `deferred`
@@ -1 +1 @@
1
- {"version":3,"file":"display-status.d.ts","sourceRoot":"","sources":["../src/display-status.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE3D;;;GAGG;AACH,MAAM,MAAM,cAAc,GACtB,SAAS,GACT,aAAa,GACb,SAAS,GACT,SAAS,GACT,UAAU,GACV,MAAM,GACN,UAAU,GACV,UAAU,CAAC;AAEf;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG,cAAc,GAAG,SAAS,GAAG,QAAQ,CAAC;AAElE,+CAA+C;AAC/C,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,yDAAyD;AACzD,MAAM,WAAW,aAAa;IAC5B,uDAAuD;IACvD,aAAa,EAAE,aAAa,CAAC;IAC7B,wDAAwD;IACxD,SAAS,EAAE,eAAe,CAAC;IAC3B;+CAC2C;IAC3C,UAAU,EAAE,OAAO,CAAC;IACpB,8DAA8D;IAC9D,aAAa,EAAE,MAAM,CAAC;IACtB,8DAA8D;IAC9D,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAMD,iFAAiF;AACjF,wBAAgB,cAAc,CAAC,QAAQ,EAAE,SAAS,cAAc,EAAE,GAAG,eAAe,CAkBnF;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,mBAAmB,CAAC,aAAa,EAAE,SAAS,cAAc,EAAE,GAAG,aAAa,CAiE3F;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAcrE;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,UAAU,GAAG,WAAW,GAAG,cAAc,CAIpF"}
1
+ {"version":3,"file":"display-status.d.ts","sourceRoot":"","sources":["../src/display-status.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE3D;;;GAGG;AACH,MAAM,MAAM,cAAc,GACtB,SAAS,GACT,aAAa,GACb,QAAQ,GACR,SAAS,GACT,SAAS,GACT,UAAU,GACV,MAAM,GACN,UAAU,GACV,UAAU,CAAC;AAEf;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG,cAAc,GAAG,SAAS,GAAG,QAAQ,CAAC;AAElE,+CAA+C;AAC/C,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,yDAAyD;AACzD,MAAM,WAAW,aAAa;IAC5B,uDAAuD;IACvD,aAAa,EAAE,aAAa,CAAC;IAC7B,wDAAwD;IACxD,SAAS,EAAE,eAAe,CAAC;IAC3B;+CAC2C;IAC3C,UAAU,EAAE,OAAO,CAAC;IACpB,8DAA8D;IAC9D,aAAa,EAAE,MAAM,CAAC;IACtB,8DAA8D;IAC9D,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAMD,iFAAiF;AACjF,wBAAgB,cAAc,CAAC,QAAQ,EAAE,SAAS,cAAc,EAAE,GAAG,eAAe,CAmBnF;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,mBAAmB,CAAC,aAAa,EAAE,SAAS,cAAc,EAAE,GAAG,aAAa,CAsE3F;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAerE;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,UAAU,GAAG,WAAW,GAAG,cAAc,CAIpF"}
@@ -14,16 +14,16 @@
14
14
  *
15
15
  * These are NEVER persisted: they are computed on demand from children's
16
16
  * canonical workflow statuses. The canonical workflow model
17
- * (`planned | in-progress | waiting | blocked | deferred | done | canceled |
18
- * rejected`) is unchanged.
17
+ * (`planned | in-progress | paused | waiting | blocked | deferred | done |
18
+ * canceled | rejected`) includes paused leaf work without implying active execution.
19
19
  */
20
20
  const ACTIVE = new Set(["in-progress"]);
21
- const OPEN = new Set(["planned", "waiting", "blocked", "deferred"]);
21
+ const OPEN = new Set(["planned", "paused", "waiting", "blocked", "deferred"]);
22
22
  const TERMINAL = new Set(["done", "canceled", "rejected"]);
23
23
  /** Count children per canonical workflow status. Pure; does not mutate input. */
24
24
  export function countBreakdown(statuses) {
25
25
  const breakdown = {
26
- planned: 0, inProgress: 0, waiting: 0, blocked: 0,
26
+ planned: 0, inProgress: 0, paused: 0, waiting: 0, blocked: 0,
27
27
  deferred: 0, done: 0, canceled: 0, rejected: 0,
28
28
  };
29
29
  for (const s of statuses) {
@@ -34,6 +34,9 @@ export function countBreakdown(statuses) {
34
34
  case "in-progress":
35
35
  breakdown.inProgress++;
36
36
  break;
37
+ case "paused":
38
+ breakdown.paused++;
39
+ break;
37
40
  case "waiting":
38
41
  breakdown.waiting++;
39
42
  break;
@@ -57,7 +60,7 @@ export function countBreakdown(statuses) {
57
60
  return breakdown;
58
61
  }
59
62
  function emptyBreakdown() {
60
- return { planned: 0, inProgress: 0, waiting: 0, blocked: 0, deferred: 0, done: 0, canceled: 0, rejected: 0 };
63
+ return { planned: 0, inProgress: 0, paused: 0, waiting: 0, blocked: 0, deferred: 0, done: 0, canceled: 0, rejected: 0 };
61
64
  }
62
65
  /**
63
66
  * Derive the parent display snapshot from its children's canonical statuses.
@@ -70,6 +73,7 @@ function emptyBreakdown() {
70
73
  * - all `rejected` → `rejected`
71
74
  * - otherwise → `closed` (mixed terminal outcomes)
72
75
  * 3. Compute `unfinished = meaningful ∩ OPEN`.
76
+ * - homogeneous `paused` → `paused`
73
77
  * - homogeneous `waiting` → `waiting`
74
78
  * - homogeneous `blocked` → `blocked`
75
79
  * - homogeneous `deferred` → `deferred`
@@ -121,6 +125,10 @@ export function deriveParentDisplay(childStatuses) {
121
125
  }
122
126
  // 3. Unfinished meaningful remainder.
123
127
  const unfinished = meaningful.filter((s) => OPEN.has(s));
128
+ const allPaused = unfinished.length > 0 && unfinished.every((s) => s === "paused");
129
+ if (allPaused) {
130
+ return { displayStatus: "paused", breakdown, hasStarted, totalChildren, meaningfulChildren };
131
+ }
124
132
  const allWaiting = unfinished.length > 0 && unfinished.every((s) => s === "waiting");
125
133
  if (allWaiting) {
126
134
  return { displayStatus: "waiting", breakdown, hasStarted, totalChildren, meaningfulChildren };
@@ -150,6 +158,7 @@ export function toWorkflowStatus(value) {
150
158
  switch (value) {
151
159
  case "planned":
152
160
  case "in-progress":
161
+ case "paused":
153
162
  case "waiting":
154
163
  case "blocked":
155
164
  case "deferred":
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { type Feature, type FeaturesDocument, type Manifest, type Phase, type PlanWorkspace, type Project, type RequirementsDocument, type Requirement, type ActivityEntry, type ActivityLog, type CodebaseProfile, type ResumeFocus, type WorkDeviation } from "./schema.js";
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
4
  export interface PlanStoreErrorDetails {
5
5
  path?: string;
@@ -117,6 +117,10 @@ export declare class PlanStore {
117
117
  runBatch<T>(fn: () => Promise<T>): Promise<T>;
118
118
  private maybeAutoSync;
119
119
  private normalizeTasks;
120
+ /** Stamp description edits independently from generic entity mutations.
121
+ * Legacy entities cannot reveal their historical description-edit time, so
122
+ * their creation time is the earliest truthful fallback. */
123
+ private stampDescriptionUpdatedAt;
120
124
  private normalizeFeaturesDocument;
121
125
  private normalizePhaseDocument;
122
126
  private normalizeStructureSnapshot;
@@ -316,8 +320,8 @@ export declare class PlanStore {
316
320
  updateProject(updater: (p: Project) => Project): Promise<Project>;
317
321
  /** Persist an explicitly approved work deviation without coupling it to a harness. */
318
322
  addWorkDeviation(deviation: WorkDeviation): Promise<Project>;
319
- /** Mark an approved/active deviation as resolved or canceled while retaining its audit record. */
320
- setWorkDeviationState(id: string, state: "active" | "resolved" | "canceled", timestamp?: string): Promise<Project>;
323
+ /** Advance a deviation while retaining its complete audit and return stack. */
324
+ setWorkDeviationState(id: string, state: "active" | "resume-required" | "resolved" | "resumed" | "canceled", timestamp?: string): Promise<Project>;
321
325
  updateFeatures(updater: (f: FeaturesDocument) => FeaturesDocument): Promise<FeaturesDocument>;
322
326
  updateRequirements(updater: (r: RequirementsDocument) => RequirementsDocument): Promise<RequirementsDocument>;
323
327
  saveProject(project: Project): Promise<void>;
@@ -332,6 +336,10 @@ export declare class PlanStore {
332
336
  * task_create / phase_update calls on the SAME phaseId so batch operations
333
337
  * don't lose tasks (last-write-wins race condition). */
334
338
  updatePhase(phaseId: string, updater: (phase: Phase) => Phase): Promise<Phase>;
339
+ /** Pause active work with a mandatory durable checkpoint. */
340
+ pauseTask(phaseId: string, taskId: string, input: TaskPauseSnapshot): Promise<Task>;
341
+ /** Resume a paused task without resetting its original startedAt. */
342
+ resumeTask(phaseId: string, taskId: string, timestamp?: string): Promise<Task>;
335
343
  /** Get the handoff text for a phase ("" if none). Throws if phase missing. */
336
344
  getPhaseHandoff(phaseId: string): Promise<string>;
337
345
  /** Set the handoff text for a phase + stamp handoffUpdatedAt. A completed or
@@ -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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"}
@@ -14,7 +14,7 @@ const PLANNER_GITIGNORE = [
14
14
  "generated/",
15
15
  "",
16
16
  ].join("\n");
17
- import { CodebaseProfileSchema, FeatureSchema, FeaturesDocumentSchema, ManifestSchema, PhaseSchema, ProjectSchema, RequirementsDocumentSchema, ResumeFocusSchema, ActivityLogSchema, TimestampSchema, } from "./schema.js";
17
+ import { CodebaseProfileSchema, FeatureSchema, FeaturesDocumentSchema, ManifestSchema, PhaseSchema, TaskPauseSnapshotSchema, ProjectSchema, RequirementsDocumentSchema, ResumeFocusSchema, ActivityLogSchema, TimestampSchema, } from "./schema.js";
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
  function nowISO() {
@@ -518,23 +518,43 @@ export class PlanStore {
518
518
  normalizeTasks(tasks) {
519
519
  // Numbers are a STABLE global sequence (assigned once at create from project.nextTaskNumber).
520
520
  // Do NOT renumber here — renumbering would break references after deletions.
521
- return { tasks, changed: false };
521
+ const normalized = tasks.map((task) => task.description && !task.descriptionUpdatedAt
522
+ ? { ...task, descriptionUpdatedAt: task.createdAt }
523
+ : task);
524
+ return { tasks: normalized, changed: normalized.some((task, index) => task !== tasks[index]) };
525
+ }
526
+ /** Stamp description edits independently from generic entity mutations.
527
+ * Legacy entities cannot reveal their historical description-edit time, so
528
+ * their creation time is the earliest truthful fallback. */
529
+ stampDescriptionUpdatedAt(entity, previousDescription, timestamp) {
530
+ if (!entity.description)
531
+ return { ...entity, descriptionUpdatedAt: "" };
532
+ if (previousDescription === undefined || previousDescription !== entity.description) {
533
+ return { ...entity, descriptionUpdatedAt: timestamp };
534
+ }
535
+ return entity.descriptionUpdatedAt ? entity : { ...entity, descriptionUpdatedAt: entity.createdAt };
522
536
  }
523
537
  normalizeFeaturesDocument(doc) {
524
538
  // Numbers are a STABLE global sequence (assigned once at create from project.nextFeatureNumber).
525
- return { doc, changed: false };
539
+ const features = doc.features.map((feature) => feature.description && !feature.descriptionUpdatedAt
540
+ ? { ...feature, descriptionUpdatedAt: feature.createdAt }
541
+ : feature);
542
+ return { doc: { ...doc, features }, changed: features.some((feature, index) => feature !== doc.features[index]) };
526
543
  }
527
544
  normalizePhaseDocument(phase) {
528
545
  const { tasks, changed } = this.normalizeTasks(phase.tasks);
529
546
  const nextTaskIds = tasks.map((task) => task.id);
530
547
  const taskIdsChanged = nextTaskIds.length !== phase.taskIds.length || nextTaskIds.some((id, index) => id !== phase.taskIds[index]);
548
+ const descriptionUpdatedAt = phase.description && !phase.descriptionUpdatedAt ? phase.createdAt : phase.descriptionUpdatedAt;
549
+ const descriptionTimestampChanged = descriptionUpdatedAt !== phase.descriptionUpdatedAt;
531
550
  return {
532
551
  phase: {
533
552
  ...phase,
553
+ descriptionUpdatedAt,
534
554
  tasks,
535
555
  taskIds: nextTaskIds,
536
556
  },
537
- changed: changed || taskIdsChanged,
557
+ changed: changed || taskIdsChanged || descriptionTimestampChanged,
538
558
  };
539
559
  }
540
560
  normalizeStructureSnapshot(featuresDoc, phases) {
@@ -1013,7 +1033,10 @@ export class PlanStore {
1013
1033
  const raws = await this.loadRawFeatures();
1014
1034
  const phases = await this.loadAllPhases();
1015
1035
  const features = raws.map((f) => ({ ...f, status: this.deriveFeatureStatus(f.id, phases) }));
1016
- return this.normalizeStructureSnapshot({ features }, phases).features;
1036
+ // Keep legacy feature descriptions displayable without rewriting on read.
1037
+ // Phase/task reads already apply the equivalent creation-date fallback.
1038
+ const normalizedFeatures = this.normalizeFeaturesDocument({ features }).doc.features;
1039
+ return this.normalizeStructureSnapshot({ features: normalizedFeatures }, phases).features;
1017
1040
  }
1018
1041
  async loadCodebaseProfile() {
1019
1042
  try {
@@ -1569,27 +1592,32 @@ export class PlanStore {
1569
1592
  return "done";
1570
1593
  const hasDone = meaningful.some((s) => s === "done");
1571
1594
  const hasActive = meaningful.some((s) => s === "in-progress");
1595
+ const hasPaused = meaningful.some((s) => s === "paused");
1572
1596
  const hasPlanned = meaningful.some((s) => s === "planned");
1573
1597
  const hasBlocked = meaningful.some((s) => s === "blocked");
1574
1598
  const hasWaiting = meaningful.some((s) => s === "waiting");
1575
1599
  const hasDeferred = meaningful.some((s) => s === "deferred");
1576
1600
  if (hasActive)
1577
1601
  return "in-progress";
1578
- // If completed work exists and the ONLY remaining meaningful work is deferred,
1579
- // surface deferred instead of implying active execution.
1580
- if (hasDone && !hasPlanned && !hasBlocked && !hasWaiting && hasDeferred)
1602
+ // If completed work exists and the ONLY remaining meaningful work is paused
1603
+ // or deferred, do not imply active execution.
1604
+ if (hasDone && !hasPlanned && !hasBlocked && !hasWaiting && !hasDeferred && hasPaused)
1605
+ return "paused";
1606
+ if (hasDone && !hasPlanned && !hasBlocked && !hasWaiting && !hasPaused && hasDeferred)
1581
1607
  return "deferred";
1582
1608
  // Partial completion with remaining planned/blocked/waiting work still means
1583
1609
  // the phase has genuinely started and is not terminal yet.
1584
1610
  if (hasDone)
1585
1611
  return "in-progress";
1586
- // No progress at all ⇒ surface the stall / not-started state (blocked > waiting > deferred > planned).
1612
+ // No progress at all ⇒ surface the stall / not-started state.
1587
1613
  if (hasBlocked)
1588
1614
  return "blocked";
1589
1615
  if (hasWaiting)
1590
1616
  return "waiting";
1591
1617
  if (hasDeferred)
1592
1618
  return "deferred";
1619
+ if (hasPaused)
1620
+ return "paused";
1593
1621
  return "planned";
1594
1622
  }
1595
1623
  deriveFeatureStatus(featureId, phases) {
@@ -1605,14 +1633,17 @@ export class PlanStore {
1605
1633
  return "done";
1606
1634
  const hasDone = meaningful.some((s) => s === "done");
1607
1635
  const hasActive = meaningful.some((s) => s === "discovery" || s === "in-progress");
1636
+ const hasPaused = meaningful.some((s) => s === "paused");
1608
1637
  const hasPlanned = meaningful.some((s) => s === "planned");
1609
1638
  const hasBlocked = meaningful.some((s) => s === "blocked");
1610
1639
  const hasWaiting = meaningful.some((s) => s === "waiting");
1611
1640
  const hasDeferred = meaningful.some((s) => s === "deferred");
1612
1641
  if (hasActive)
1613
1642
  return "in-progress";
1614
- // Same rule as phases: done + deferred-only remainder is deferred, not active.
1615
- if (hasDone && !hasPlanned && !hasBlocked && !hasWaiting && hasDeferred)
1643
+ // Same rule as phases: done + paused/deferred-only remainder is non-active.
1644
+ if (hasDone && !hasPlanned && !hasBlocked && !hasWaiting && !hasDeferred && hasPaused)
1645
+ return "paused";
1646
+ if (hasDone && !hasPlanned && !hasBlocked && !hasWaiting && !hasPaused && hasDeferred)
1616
1647
  return "deferred";
1617
1648
  if (hasDone)
1618
1649
  return "in-progress";
@@ -1623,6 +1654,8 @@ export class PlanStore {
1623
1654
  return "waiting";
1624
1655
  if (hasDeferred)
1625
1656
  return "deferred";
1657
+ if (hasPaused)
1658
+ return "paused";
1626
1659
  return "planned";
1627
1660
  }
1628
1661
  async syncStatuses() {
@@ -1712,7 +1745,7 @@ export class PlanStore {
1712
1745
  workDeviations: [...project.workDeviations, deviation],
1713
1746
  }));
1714
1747
  }
1715
- /** Mark an approved/active deviation as resolved or canceled while retaining its audit record. */
1748
+ /** Advance a deviation while retaining its complete audit and return stack. */
1716
1749
  async setWorkDeviationState(id, state, timestamp = nowISO()) {
1717
1750
  return this.updateProject((project) => ({
1718
1751
  ...project,
@@ -1720,7 +1753,9 @@ export class PlanStore {
1720
1753
  ...deviation,
1721
1754
  state,
1722
1755
  activatedAt: state === "active" ? timestamp : deviation.activatedAt,
1756
+ resumeRequiredAt: state === "resume-required" ? timestamp : deviation.resumeRequiredAt,
1723
1757
  resolvedAt: state === "resolved" || state === "canceled" ? timestamp : deviation.resolvedAt,
1758
+ resumedAt: state === "resumed" ? timestamp : deviation.resumedAt,
1724
1759
  }),
1725
1760
  }));
1726
1761
  }
@@ -1728,7 +1763,15 @@ export class PlanStore {
1728
1763
  const updated = await this.withFeaturesLock(async () => {
1729
1764
  await this.migrateLegacy();
1730
1765
  const current = await this.loadFeatures();
1731
- const upd = this.normalizeFeaturesDocument(updater(current)).doc;
1766
+ // Updaters commonly mutate `current` in place, so snapshot descriptions
1767
+ // before invoking them rather than comparing object references afterward.
1768
+ const previousDescriptions = new Map(current.features.map((feature) => [feature.id, feature.description]));
1769
+ const timestamp = nowISO();
1770
+ const candidate = updater(current);
1771
+ const stamped = {
1772
+ features: candidate.features.map((feature) => this.stampDescriptionUpdatedAt(feature, previousDescriptions.get(feature.id), timestamp)),
1773
+ };
1774
+ const upd = this.normalizeFeaturesDocument(stamped).doc;
1732
1775
  await this.saveFeaturesRaw(upd);
1733
1776
  return upd;
1734
1777
  });
@@ -1749,7 +1792,11 @@ export class PlanStore {
1749
1792
  async saveFeatures(features) {
1750
1793
  await this.withFeaturesLock(async () => {
1751
1794
  await this.migrateLegacy();
1752
- await this.saveFeaturesRaw(features);
1795
+ const previousDescriptions = new Map((await this.loadRawFeatures()).map((feature) => [feature.id, feature.description]));
1796
+ const timestamp = nowISO();
1797
+ await this.saveFeaturesRaw({
1798
+ features: features.features.map((feature) => this.stampDescriptionUpdatedAt(feature, previousDescriptions.get(feature.id), timestamp)),
1799
+ });
1753
1800
  });
1754
1801
  await this.touchTimestamp();
1755
1802
  await this.maybeAutoSync();
@@ -1782,8 +1829,9 @@ export class PlanStore {
1782
1829
  async saveFeature(feature) {
1783
1830
  await this.withFeaturesLock(async () => {
1784
1831
  await this.migrateLegacy();
1832
+ const previous = await readJson(this.featurePath(feature.id), FeatureSchema).catch(() => null);
1785
1833
  await mkdir(this.featuresDir(), { recursive: true });
1786
- const parsed = FeatureSchema.parse(feature);
1834
+ const parsed = FeatureSchema.parse(this.stampDescriptionUpdatedAt(feature, previous?.description, nowISO()));
1787
1835
  await atomicWriteJson(this.featurePath(parsed.id), parsed, this.root);
1788
1836
  });
1789
1837
  await this.touchTimestamp();
@@ -1795,6 +1843,8 @@ export class PlanStore {
1795
1843
  await this.touchTimestamp();
1796
1844
  }
1797
1845
  async savePhase(phase) {
1846
+ const previous = await this.loadPhase(phase.id).catch(() => null);
1847
+ const timestamp = nowISO();
1798
1848
  const features = await this.loadRawFeatures();
1799
1849
  const resolvedFeatureId = resolveStoredFeatureId(features, phase.featureId);
1800
1850
  // Referential integrity: if a featureId is present but cannot be resolved
@@ -1810,7 +1860,10 @@ export class PlanStore {
1810
1860
  const normalizedInput = resolvedFeatureId && resolvedFeatureId !== phase.featureId
1811
1861
  ? { ...phase, featureId: resolvedFeatureId }
1812
1862
  : phase;
1813
- const parsed = PhaseSchema.parse(this.normalizePhaseDocument(normalizedInput).phase);
1863
+ const previousTaskDescriptions = new Map((previous?.tasks ?? []).map((task) => [task.id, task.description]));
1864
+ const timestamped = this.stampDescriptionUpdatedAt(normalizedInput, previous?.description, timestamp);
1865
+ timestamped.tasks = timestamped.tasks.map((task) => this.stampDescriptionUpdatedAt(task, previousTaskDescriptions.get(task.id), timestamp));
1866
+ const parsed = PhaseSchema.parse(this.normalizePhaseDocument(timestamped).phase);
1814
1867
  await mkdir(this.phasesDir(), { recursive: true });
1815
1868
  await atomicWriteJson(this.phasePath(parsed.id), parsed, this.root);
1816
1869
  await this.touchTimestamp();
@@ -1827,20 +1880,96 @@ export class PlanStore {
1827
1880
  // not persisted); the return value is re-derived for the caller.
1828
1881
  const raw = await atomicUpdateJson(this.phasePath(phaseId), PhaseSchema, (rawPhase) => {
1829
1882
  const current = { ...rawPhase, status: this.derivePhaseStatus(rawPhase.tasks) };
1883
+ // The updater may mutate `current`, therefore snapshot descriptions first.
1884
+ const previousDescription = current.description;
1885
+ const previousTaskDescriptions = new Map(current.tasks.map((task) => [task.id, task.description]));
1886
+ const timestamp = nowISO();
1830
1887
  const next = updater(current);
1831
- const resolvedFeatureId = resolveStoredFeatureId(features, next.featureId);
1888
+ const timestamped = this.stampDescriptionUpdatedAt(next, previousDescription, timestamp);
1889
+ timestamped.tasks = timestamped.tasks.map((task) => this.stampDescriptionUpdatedAt(task, previousTaskDescriptions.get(task.id), timestamp));
1890
+ const resolvedFeatureId = resolveStoredFeatureId(features, timestamped.featureId);
1832
1891
  // Referential integrity: reject orphan featureId.
1833
- if (next.featureId && next.featureId.trim() && !resolvedFeatureId) {
1834
- throw new PlanStoreError(`Cannot update phase: featureId "${next.featureId}" does not match any existing feature.`);
1892
+ if (timestamped.featureId && timestamped.featureId.trim() && !resolvedFeatureId) {
1893
+ throw new PlanStoreError(`Cannot update phase: featureId "${timestamped.featureId}" does not match any existing feature.`);
1835
1894
  }
1836
- const normalizedInput = resolvedFeatureId && resolvedFeatureId !== next.featureId
1837
- ? { ...next, featureId: resolvedFeatureId }
1838
- : next;
1895
+ const normalizedInput = resolvedFeatureId && resolvedFeatureId !== timestamped.featureId
1896
+ ? { ...timestamped, featureId: resolvedFeatureId }
1897
+ : timestamped;
1839
1898
  return this.normalizePhaseDocument(normalizedInput).phase;
1840
1899
  });
1841
1900
  await this.maybeAutoSync();
1842
1901
  return { ...raw, status: this.derivePhaseStatus(raw.tasks) };
1843
1902
  }
1903
+ /** Pause active work with a mandatory durable checkpoint. */
1904
+ async pauseTask(phaseId, taskId, input) {
1905
+ const snapshot = TaskPauseSnapshotSchema.parse(input);
1906
+ let paused;
1907
+ await this.updatePhase(phaseId, (phase) => {
1908
+ const task = phase.tasks.find((candidate) => candidate.id === taskId);
1909
+ if (!task)
1910
+ throw new PlanStoreError(`Task ${taskId} does not belong to phase ${phaseId}.`);
1911
+ if (task.status !== "in-progress") {
1912
+ throw new PlanStoreError(`Task ${taskId} cannot be paused from ${task.status}; only in-progress work can be paused.`);
1913
+ }
1914
+ const description = [
1915
+ `Reason: ${snapshot.reason}`,
1916
+ `What was being done: ${snapshot.whatWasBeingDone}`,
1917
+ `Resume location: ${snapshot.resumeLocation}`,
1918
+ `How to resume: ${snapshot.howToResume}`,
1919
+ ].join("\n");
1920
+ paused = {
1921
+ ...task,
1922
+ status: "paused",
1923
+ pauseSnapshot: snapshot,
1924
+ pauseHistory: [...task.pauseHistory, snapshot],
1925
+ statusLog: [...task.statusLog, {
1926
+ id: createStatusLogEntryId(),
1927
+ date: snapshot.pausedAt,
1928
+ fromStatus: "in-progress",
1929
+ toStatus: "paused",
1930
+ title: "in-progress → paused",
1931
+ description,
1932
+ }],
1933
+ updatedAt: snapshot.pausedAt,
1934
+ };
1935
+ phase.tasks = phase.tasks.map((candidate) => candidate.id === taskId ? paused : candidate);
1936
+ return phase;
1937
+ });
1938
+ return paused;
1939
+ }
1940
+ /** Resume a paused task without resetting its original startedAt. */
1941
+ async resumeTask(phaseId, taskId, timestamp = nowISO()) {
1942
+ let resumed;
1943
+ await this.updatePhase(phaseId, (phase) => {
1944
+ const task = phase.tasks.find((candidate) => candidate.id === taskId);
1945
+ if (!task)
1946
+ throw new PlanStoreError(`Task ${taskId} does not belong to phase ${phaseId}.`);
1947
+ if (task.status !== "paused") {
1948
+ throw new PlanStoreError(`Task ${taskId} cannot be resumed from ${task.status}; only paused work can be resumed.`);
1949
+ }
1950
+ const snapshot = task.pauseSnapshot;
1951
+ resumed = {
1952
+ ...task,
1953
+ status: "in-progress",
1954
+ pauseSnapshot: null,
1955
+ startedAt: task.startedAt || timestamp,
1956
+ statusLog: [...task.statusLog, {
1957
+ id: createStatusLogEntryId(),
1958
+ date: timestamp,
1959
+ fromStatus: "paused",
1960
+ toStatus: "in-progress",
1961
+ title: "paused → in-progress",
1962
+ description: snapshot
1963
+ ? `Resumed from ${snapshot.resumeLocation}. ${snapshot.howToResume}`
1964
+ : "Paused task resumed.",
1965
+ }],
1966
+ updatedAt: timestamp,
1967
+ };
1968
+ phase.tasks = phase.tasks.map((candidate) => candidate.id === taskId ? resumed : candidate);
1969
+ return phase;
1970
+ });
1971
+ return resumed;
1972
+ }
1844
1973
  // ── Phase-scoped handoff (entity field, harness-agnostic) ────────────
1845
1974
  /** Get the handoff text for a phase ("" if none). Throws if phase missing. */
1846
1975
  async getPhaseHandoff(phaseId) {
@@ -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,CAkJhH"}
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,CAmOhH"}
package/dist/recap.js CHANGED
@@ -33,6 +33,20 @@ export async function buildRecap(st, web = {}, opts = {}) {
33
33
  const totalT = allTasks.length;
34
34
  const doneT = allTasks.filter(({ task }) => task.status === "done").length;
35
35
  const activeT = allTasks.filter(({ task }) => task.status === "in-progress").length;
36
+ const pausedTasks = allTasks.filter(({ task }) => task.status === "paused");
37
+ const pausedT = pausedTasks.length;
38
+ const pendingDeviation = [...plan.project.workDeviations]
39
+ .filter((deviation) => deviation.state === "resume-required" || deviation.state === "resolved")
40
+ .sort((left, right) => right.createdAt.localeCompare(left.createdAt))
41
+ .find((deviation) => allTasks.some(({ task }) => task.id === deviation.resumeTaskId
42
+ && (task.status === "paused" || task.status === "planned" || task.status === "waiting")));
43
+ const pendingResume = pendingDeviation
44
+ ? allTasks.find(({ task }) => task.id === pendingDeviation.resumeTaskId)
45
+ : undefined;
46
+ const standalonePaused = pausedTasks
47
+ .filter(({ task }) => task.id !== pendingResume?.task.id)
48
+ .sort((left, right) => (right.task.pauseSnapshot?.pausedAt ?? "").localeCompare(left.task.pauseSnapshot?.pausedAt ?? ""));
49
+ const latestStandalonePaused = standalonePaused[0];
36
50
  // Plan is fully complete: there is work and all of it is done, nothing active.
37
51
  // (totalT > 0 guards the empty/unstarted case from looking "complete".)
38
52
  const planComplete = totalT > 0 && doneT === totalT && doneP === totalP && doneF === totalF;
@@ -54,14 +68,24 @@ export async function buildRecap(st, web = {}, opts = {}) {
54
68
  const name = plan.project.name || "(unnamed project)";
55
69
  lines.push(`${italian ? "Progetto" : "Project"}: ${name}${plan.project.goal ? " — " + plan.project.goal : ""}`);
56
70
  lines.push(italian
57
- ? `Avanzamento: feature ${doneF}/${totalF} completate (${activeF} attive) · fasi ${doneP}/${totalP} completate (${activeP} attive) · task ${doneT}/${totalT} completati (${activeT} attivi)`
58
- : `Progress: Features ${doneF}/${totalF} done (${activeF} active) · Phases ${doneP}/${totalP} done (${activeP} active) · Tasks ${doneT}/${totalT} done (${activeT} active)`);
71
+ ? `Avanzamento: feature ${doneF}/${totalF} completate (${activeF} attive) · fasi ${doneP}/${totalP} completate (${activeP} attive) · task ${doneT}/${totalT} completati (${activeT} attivi, ${pausedT} in pausa)`
72
+ : `Progress: Features ${doneF}/${totalF} done (${activeF} active) · Phases ${doneP}/${totalP} done (${activeP} active) · Tasks ${doneT}/${totalT} done (${activeT} active, ${pausedT} paused)`);
59
73
  if (focusTask && focusPhase) {
60
74
  const fr = focusFeature ? fref(focusFeature.number) : "?";
61
75
  const pr = formatPhaseRef(focusPhase.number, focusFeature?.number);
62
76
  const tr = tref(focusTask.task.number);
63
77
  lines.push(`${italian ? "Focus corrente" : "Current focus"}: ${fr} — ${focusFeature?.name ?? "?"} / ${pr} — ${focusPhase.title} / ${tr} — ${focusTask.task.title} (in-progress)`);
64
78
  }
79
+ else if (pendingResume) {
80
+ const feature = feats.find((entry) => entry.id === pendingResume.phase.featureId);
81
+ const ref = `${formatPhaseRef(pendingResume.phase.number, feature?.number)}/${tref(pendingResume.task.number)}`;
82
+ lines.push(`${italian ? "Focus corrente" : "Current focus"}: ${italian ? "ripresa obbligatoria" : "resume required"} — ${ref} — ${pendingResume.task.title} (${pendingResume.task.status})`);
83
+ }
84
+ else if (latestStandalonePaused) {
85
+ const feature = feats.find((entry) => entry.id === latestStandalonePaused.phase.featureId);
86
+ const ref = `${formatPhaseRef(latestStandalonePaused.phase.number, feature?.number)}/${tref(latestStandalonePaused.task.number)}`;
87
+ lines.push(`${italian ? "Focus corrente" : "Current focus"}: ${italian ? "task in pausa da riprendere" : "paused task to resume"} — ${ref} — ${latestStandalonePaused.task.title}`);
88
+ }
65
89
  else if (handoffs.length > 0) {
66
90
  const top = handoffs[0];
67
91
  lines.push(`${italian ? "Focus corrente" : "Current focus"}: ${italian ? "nessun task attivo" : "no active task"} · ${italian ? "handoff pendente più recente" : "most recent pending handoff"}: ${top.compositeRef} — "${top.firstLine}"`);
@@ -79,7 +103,21 @@ export async function buildRecap(st, web = {}, opts = {}) {
79
103
  // instead of surfacing potentially-stale resume.json nextSteps. When no
80
104
  // handoff exists, fall back to resume.nextSteps but mark them as possibly
81
105
  // stale (free-text that refreshResume never touches, so they can drift).
82
- if (handoffs.length > 0) {
106
+ if (pendingResume) {
107
+ const feature = feats.find((entry) => entry.id === pendingResume.phase.featureId);
108
+ const ref = `${formatPhaseRef(pendingResume.phase.number, feature?.number)}/${tref(pendingResume.task.number)}`;
109
+ lines.push(italian
110
+ ? `Prossimo step: riprendi ${ref} con ${taskStartCmd}. Il checkpoint del task è prioritario rispetto a nuovo lavoro e handoff di fase.`
111
+ : `Next step: resume ${ref} with ${taskStartCmd}. Its task checkpoint takes precedence over new work and phase handoffs.`);
112
+ }
113
+ else if (latestStandalonePaused) {
114
+ const feature = feats.find((entry) => entry.id === latestStandalonePaused.phase.featureId);
115
+ const ref = `${formatPhaseRef(latestStandalonePaused.phase.number, feature?.number)}/${tref(latestStandalonePaused.task.number)}`;
116
+ lines.push(italian
117
+ ? `Prossimo step: riprendi il checkpoint più recente, ${ref}, con ${taskStartCmd}, prima di scegliere nuovo lavoro.`
118
+ : `Next step: resume the newest checkpoint, ${ref}, with ${taskStartCmd} before selecting new work.`);
119
+ }
120
+ else if (handoffs.length > 0) {
83
121
  lines.push(italian
84
122
  ? `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.`
85
123
  : `Next step: read the pending phase handoff below (authoritative, actively maintained). Legacy resume.json nextSteps are suppressed because they may be stale.`);
@@ -95,11 +133,31 @@ export async function buildRecap(st, web = {}, opts = {}) {
95
133
  : `⚠️ nextSteps are free-text from resume.json — may be stale; verify against current state before acting.`);
96
134
  lines.push(staleNote);
97
135
  }
136
+ if (pendingResume) {
137
+ const feature = feats.find((entry) => entry.id === pendingResume.phase.featureId);
138
+ const ref = `${formatPhaseRef(pendingResume.phase.number, feature?.number)}/${tref(pendingResume.task.number)}`;
139
+ const snapshot = pendingResume.task.pauseSnapshot ?? pendingDeviation?.snapshot;
140
+ lines.push("", italian ? "## Ripresa task obbligatoria" : "## Task resume required", `${ref} — ${pendingResume.task.title}`, snapshot ? `${italian ? "Perché è stato sospeso" : "Paused because"}: ${snapshot.reason}` : "", snapshot ? `${italian ? "Stato del lavoro" : "Work checkpoint"}: ${snapshot.whatWasBeingDone}` : "", snapshot ? `${italian ? "Riprendi da" : "Resume from"}: ${snapshot.resumeLocation}` : "", snapshot ? `${italian ? "Come riprendere" : "How to resume"}: ${snapshot.howToResume}` : "", `${italian ? "Azione" : "Action"}: ${taskStartCmd} ${ref}`);
141
+ }
142
+ if (standalonePaused.length > 0) {
143
+ lines.push("", italian ? `## Task in pausa (${standalonePaused.length})` : `## Paused tasks (${standalonePaused.length})`);
144
+ for (const entry of standalonePaused) {
145
+ const feature = feats.find((item) => item.id === entry.phase.featureId);
146
+ const ref = `${formatPhaseRef(entry.phase.number, feature?.number)}/${tref(entry.task.number)}`;
147
+ const snapshot = entry.task.pauseSnapshot;
148
+ lines.push(`${ref} — ${entry.task.title}`, snapshot ? ` ${italian ? "Perché" : "Why"}: ${snapshot.reason}` : "", snapshot ? ` ${italian ? "Stato" : "Checkpoint"}: ${snapshot.whatWasBeingDone}` : "", snapshot ? ` ${italian ? "Riprendi da" : "Resume from"}: ${snapshot.resumeLocation}` : "", snapshot ? ` ${italian ? "Come" : "How"}: ${snapshot.howToResume}` : "");
149
+ }
150
+ }
98
151
  if (handoffs.length > 0) {
99
152
  const top = handoffs[0];
100
153
  lines.push("", italian ? `## Handoff di fase pendenti (${handoffs.length})` : `## Pending phase handoffs (${handoffs.length})`);
101
154
  handoffs.forEach((h, i) => lines.push(`[${i + 1}] ${h.compositeRef} — ${h.updatedAt} — "${h.firstLine}"`));
102
- if (handoffs.length === 1) {
155
+ if (pendingResume || latestStandalonePaused) {
156
+ lines.push("", italian
157
+ ? "→ Questi handoff restano disponibili come contesto, ma prima risolvi il task da riprendere indicato sopra."
158
+ : "→ These handoffs remain available as context, but first resolve the task resume shown above.");
159
+ }
160
+ else if (handoffs.length === 1) {
103
161
  lines.push("", italian
104
162
  ? `→ Vuoi riprendere da ${top.compositeRef}? Leggi l'handoff con ${handoffShowCmd} ${top.compositeRef} e avvia il primo task pertinente. L'handoff resta attivo finché tutti i task della fase non sono done/canceled, viene sostituito da un nuovo handoff, oppure viene cancellato esplicitamente.`
105
163
  : `→ Do you want to resume from ${top.compositeRef}? Read the handoff with ${handoffShowCmd} ${top.compositeRef} and start the first relevant task. It stays active until every phase task is done/canceled, a new handoff replaces it, or it is explicitly cleared.`);
@@ -115,7 +173,7 @@ export async function buildRecap(st, web = {}, opts = {}) {
115
173
  ? `Piano completo — aggiungi una nuova feature (${featureAddCmd}) o fase (${phaseAddCmd}) per continuare.`
116
174
  : `Plan complete — add a new feature (${featureAddCmd}) or phase (${phaseAddCmd}) to continue.`);
117
175
  }
118
- else if (activeT === 0) {
176
+ else if (activeT === 0 && !pendingResume && standalonePaused.length === 0) {
119
177
  lines.push("", italian
120
178
  ? `Nessun handoff pendente e nessun task in-progress. Usa ${taskAddCmd} / ${taskStartCmd} per iniziare.`
121
179
  : `No phase handoff pending and no task in-progress. Use ${taskAddCmd} / ${taskStartCmd} to begin work.`);