@agent-plan/core 0.2.25 → 0.2.26

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.
Files changed (48) hide show
  1. package/dist/display-status.d.ts +3 -3
  2. package/dist/display-status.d.ts.map +1 -1
  3. package/dist/display-status.js +5 -4
  4. package/dist/handoff-context.d.ts +91 -1
  5. package/dist/handoff-context.d.ts.map +1 -1
  6. package/dist/handoff-context.js +134 -2
  7. package/dist/index.d.ts +5 -1
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +4 -0
  10. package/dist/naming.d.ts +3 -0
  11. package/dist/naming.d.ts.map +1 -1
  12. package/dist/naming.js +7 -0
  13. package/dist/payload-fallback.d.ts +38 -0
  14. package/dist/payload-fallback.d.ts.map +1 -0
  15. package/dist/payload-fallback.js +73 -0
  16. package/dist/plan-store.d.ts +65 -8
  17. package/dist/plan-store.d.ts.map +1 -1
  18. package/dist/plan-store.js +391 -39
  19. package/dist/planner-rules.d.ts.map +1 -1
  20. package/dist/planner-rules.js +4 -2
  21. package/dist/planner-skill.d.ts +24 -0
  22. package/dist/planner-skill.d.ts.map +1 -0
  23. package/dist/planner-skill.js +113 -0
  24. package/dist/project-context-migration.d.ts +47 -0
  25. package/dist/project-context-migration.d.ts.map +1 -0
  26. package/dist/project-context-migration.js +168 -0
  27. package/dist/read-tracking.d.ts +20 -10
  28. package/dist/read-tracking.d.ts.map +1 -1
  29. package/dist/read-tracking.js +35 -29
  30. package/dist/recap.d.ts.map +1 -1
  31. package/dist/recap.js +1 -0
  32. package/dist/refs.d.ts +6 -1
  33. package/dist/refs.d.ts.map +1 -1
  34. package/dist/refs.js +25 -0
  35. package/dist/renderer.d.ts.map +1 -1
  36. package/dist/renderer.js +24 -1
  37. package/dist/requirement-macro-tasks.d.ts +18 -0
  38. package/dist/requirement-macro-tasks.d.ts.map +1 -0
  39. package/dist/requirement-macro-tasks.js +55 -0
  40. package/dist/schema.d.ts +1088 -273
  41. package/dist/schema.d.ts.map +1 -1
  42. package/dist/schema.js +65 -0
  43. package/dist/task-start-outcome.d.ts +1 -1
  44. package/dist/task-start-outcome.d.ts.map +1 -1
  45. package/dist/task-start-outcome.js +1 -0
  46. package/package.json +3 -1
  47. package/planner-skill.md +210 -0
  48. package/skills/grill-me/SKILL.md +10 -0
@@ -9,8 +9,8 @@
9
9
  * - `started`: the entity has clearly begun (historical progress exists) but
10
10
  * no child is active now, and the unfinished remainder is mixed or cannot
11
11
  * honestly collapse to one specific workflow label.
12
- * - `closed`: every child is terminal, but outcomes are mixed (e.g.
13
- * `done + canceled`, `canceled + rejected`).
12
+ * - `closed`: every child is terminal, but outcomes are mixed without a
13
+ * positive completion rollup (for example, `canceled + rejected`).
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
@@ -62,7 +62,7 @@ export declare function countBreakdown(statuses: readonly WorkflowStatus[]): Sta
62
62
  * Algorithm (locked by P039 accepted decisions):
63
63
  * 1. If any meaningful child is active now → `in-progress`.
64
64
  * 2. If every child is terminal:
65
- * - all `done` → `done`
65
+ * - only `done` + `canceled`, with at least one `done` → `done`
66
66
  * - all `canceled` → `canceled`
67
67
  * - all `rejected` → `rejected`
68
68
  * - otherwise → `closed` (mixed terminal outcomes)
@@ -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,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,CAoE3F;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"}
@@ -9,8 +9,8 @@
9
9
  * - `started`: the entity has clearly begun (historical progress exists) but
10
10
  * no child is active now, and the unfinished remainder is mixed or cannot
11
11
  * honestly collapse to one specific workflow label.
12
- * - `closed`: every child is terminal, but outcomes are mixed (e.g.
13
- * `done + canceled`, `canceled + rejected`).
12
+ * - `closed`: every child is terminal, but outcomes are mixed without a
13
+ * positive completion rollup (for example, `canceled + rejected`).
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
@@ -65,7 +65,7 @@ function emptyBreakdown() {
65
65
  * Algorithm (locked by P039 accepted decisions):
66
66
  * 1. If any meaningful child is active now → `in-progress`.
67
67
  * 2. If every child is terminal:
68
- * - all `done` → `done`
68
+ * - only `done` + `canceled`, with at least one `done` → `done`
69
69
  * - all `canceled` → `canceled`
70
70
  * - all `rejected` → `rejected`
71
71
  * - otherwise → `closed` (mixed terminal outcomes)
@@ -108,7 +108,8 @@ export function deriveParentDisplay(childStatuses) {
108
108
  }
109
109
  // 2. All children are terminal.
110
110
  if (statuses.every((s) => TERMINAL.has(s))) {
111
- if (statuses.every((s) => s === "done")) {
111
+ if (statuses.some((s) => s === "done")
112
+ && statuses.every((s) => s === "done" || s === "canceled")) {
112
113
  return { displayStatus: "done", breakdown, hasStarted, totalChildren, meaningfulChildren };
113
114
  }
114
115
  if (statuses.every((s) => s === "canceled")) {
@@ -1,5 +1,79 @@
1
- import type { Feature, Phase, Task } from "./schema.js";
1
+ import type { Feature, HandoffCompletenessAudit, HandoffCompletenessEntry, HandoffSupportingDocument, Phase, Task } from "./schema.js";
2
2
  export declare const COMPLETION_SUMMARY_HEADING = "**Completion summary:**";
3
+ export declare const HANDOFF_COMPLETENESS_AUDIT_VERSION = 1;
4
+ export declare const MAX_HANDOFF_CONTENT_CHARS = 24000;
5
+ export declare const HANDOFF_AUDIT_START_MARKER = "<!-- agent-plan:handoff-audit:start -->";
6
+ export declare const HANDOFF_AUDIT_END_MARKER = "<!-- agent-plan:handoff-audit:end -->";
7
+ export declare const HANDOFF_COMPLETENESS_CATEGORIES: readonly [{
8
+ readonly id: "exact-focus-resume-point";
9
+ readonly label: "Exact focus and resume point";
10
+ }, {
11
+ readonly id: "first-resume-action";
12
+ readonly label: "First resume action";
13
+ }, {
14
+ readonly id: "completed-work";
15
+ readonly label: "Completed work";
16
+ }, {
17
+ readonly id: "partial-work";
18
+ readonly label: "Partial work";
19
+ }, {
20
+ readonly id: "remaining-work";
21
+ readonly label: "Remaining work";
22
+ }, {
23
+ readonly id: "decisions-rationale";
24
+ readonly label: "Decisions and rationale";
25
+ }, {
26
+ readonly id: "rejected-alternatives";
27
+ readonly label: "Rejected alternatives";
28
+ }, {
29
+ readonly id: "files-symbols";
30
+ readonly label: "Files and symbols";
31
+ }, {
32
+ readonly id: "branch-worktree";
33
+ readonly label: "Branch and worktree";
34
+ }, {
35
+ readonly id: "commands-tools";
36
+ readonly label: "Commands and tools";
37
+ }, {
38
+ readonly id: "completed-verification";
39
+ readonly label: "Completed verification";
40
+ }, {
41
+ readonly id: "pending-verification";
42
+ readonly label: "Pending verification";
43
+ }, {
44
+ readonly id: "runtime-limitations-workarounds";
45
+ readonly label: "Runtime limitations and workarounds";
46
+ }, {
47
+ readonly id: "blockers-risks";
48
+ readonly label: "Blockers and risks";
49
+ }, {
50
+ readonly id: "user-visible-behavior";
51
+ readonly label: "User-visible behavior";
52
+ }, {
53
+ readonly id: "operator-actions";
54
+ readonly label: "Operator actions";
55
+ }, {
56
+ readonly id: "project-operating-notes";
57
+ readonly label: "Project-specific operating notes";
58
+ }, {
59
+ readonly id: "conversation-only-facts";
60
+ readonly label: "Conversation-only facts";
61
+ }];
62
+ export type HandoffCompletenessCategory = typeof HANDOFF_COMPLETENESS_CATEGORIES[number]["id"];
63
+ export type HandoffContractErrorCode = "HANDOFF_COMPLETENESS_AUDIT_REQUIRED" | "HANDOFF_CONTENT_LIMIT_EXCEEDED" | "HANDOFF_SUPPORTING_DOCUMENT_INVALID" | "HANDOFF_PERSISTENCE_VERIFICATION_FAILED";
64
+ export declare class HandoffContractError extends Error {
65
+ readonly code: HandoffContractErrorCode;
66
+ readonly details: Record<string, unknown>;
67
+ constructor(code: HandoffContractErrorCode, message: string, details?: Record<string, unknown>);
68
+ }
69
+ export interface HandoffCompletenessAuditInput {
70
+ version: number;
71
+ entries: HandoffCompletenessEntry[];
72
+ }
73
+ export interface HandoffSupportingDocumentInput {
74
+ path: string;
75
+ description: string;
76
+ }
3
77
  export interface HandoffTaskContextUpdate {
4
78
  taskId: string;
5
79
  completionSummary: string;
@@ -35,11 +109,22 @@ export interface PhaseHandoffAudit {
35
109
  number: number;
36
110
  title: string;
37
111
  }>;
112
+ completenessVersion: number;
113
+ maxContentChars: number;
114
+ completenessCategories: ReadonlyArray<{
115
+ id: HandoffCompletenessCategory;
116
+ label: string;
117
+ }>;
118
+ existingCompletenessAudit: HandoffCompletenessAudit | null;
38
119
  }
39
120
  export interface RefreshPhaseHandoffInput {
40
121
  content: string;
41
122
  expectedHandoffUpdatedAt: string;
42
123
  reconciledExistingHandoff: boolean;
124
+ completenessAudit?: HandoffCompletenessAuditInput;
125
+ supportingDocuments?: HandoffSupportingDocumentInput[];
126
+ /** Populated and verified by PlanStore before pure domain application. */
127
+ verifiedSupportingDocuments?: HandoffSupportingDocument[];
43
128
  contextSync: PhaseHandoffContextSync;
44
129
  }
45
130
  export interface RefreshPhaseHandoffResult {
@@ -47,9 +132,14 @@ export interface RefreshPhaseHandoffResult {
47
132
  feature: Feature;
48
133
  updatedTaskIds: string[];
49
134
  handoffUpdatedAt: string;
135
+ handoffAudit: HandoffCompletenessAudit;
50
136
  }
51
137
  export declare function hasTaskCompletionEvidence(task: Task): boolean;
52
138
  export declare function auditPhaseHandoff(phase: Phase, feature: Feature): PhaseHandoffAudit;
139
+ export declare function handoffContentHash(content: string): string;
140
+ export declare function validateHandoffCompletenessAudit(audit: HandoffCompletenessAuditInput | undefined): HandoffCompletenessEntry[];
141
+ export declare function renderHandoffCompletenessAudit(audit: HandoffCompletenessAuditInput): string;
142
+ export declare function renderVerifiedHandoffContent(content: string, audit?: HandoffCompletenessAuditInput): string;
53
143
  export declare function validateCanonicalHandoffContent(content: string): void;
54
144
  export declare function validateHandoffContextSync(phase: Phase, feature: Feature, input: RefreshPhaseHandoffInput): void;
55
145
  export declare function applyHandoffContextSync(phase: Phase, feature: Feature, input: RefreshPhaseHandoffInput, timestamp: string): {
@@ -1 +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"}
1
+ {"version":3,"file":"handoff-context.d.ts","sourceRoot":"","sources":["../src/handoff-context.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,39 @@
1
+ import { createHash } from "node:crypto";
1
2
  export const COMPLETION_SUMMARY_HEADING = "**Completion summary:**";
3
+ export const HANDOFF_COMPLETENESS_AUDIT_VERSION = 1;
4
+ export const MAX_HANDOFF_CONTENT_CHARS = 24_000;
5
+ export const HANDOFF_AUDIT_START_MARKER = "<!-- agent-plan:handoff-audit:start -->";
6
+ export const HANDOFF_AUDIT_END_MARKER = "<!-- agent-plan:handoff-audit:end -->";
7
+ export const HANDOFF_COMPLETENESS_CATEGORIES = [
8
+ { id: "exact-focus-resume-point", label: "Exact focus and resume point" },
9
+ { id: "first-resume-action", label: "First resume action" },
10
+ { id: "completed-work", label: "Completed work" },
11
+ { id: "partial-work", label: "Partial work" },
12
+ { id: "remaining-work", label: "Remaining work" },
13
+ { id: "decisions-rationale", label: "Decisions and rationale" },
14
+ { id: "rejected-alternatives", label: "Rejected alternatives" },
15
+ { id: "files-symbols", label: "Files and symbols" },
16
+ { id: "branch-worktree", label: "Branch and worktree" },
17
+ { id: "commands-tools", label: "Commands and tools" },
18
+ { id: "completed-verification", label: "Completed verification" },
19
+ { id: "pending-verification", label: "Pending verification" },
20
+ { id: "runtime-limitations-workarounds", label: "Runtime limitations and workarounds" },
21
+ { id: "blockers-risks", label: "Blockers and risks" },
22
+ { id: "user-visible-behavior", label: "User-visible behavior" },
23
+ { id: "operator-actions", label: "Operator actions" },
24
+ { id: "project-operating-notes", label: "Project-specific operating notes" },
25
+ { id: "conversation-only-facts", label: "Conversation-only facts" },
26
+ ];
27
+ export class HandoffContractError extends Error {
28
+ code;
29
+ details;
30
+ constructor(code, message, details = {}) {
31
+ super(message);
32
+ this.name = "HandoffContractError";
33
+ this.code = code;
34
+ this.details = details;
35
+ }
36
+ }
2
37
  export function hasTaskCompletionEvidence(task) {
3
38
  if (task.status !== "done")
4
39
  return true;
@@ -17,6 +52,10 @@ export function auditPhaseHandoff(phase, feature) {
17
52
  handoffUpdatedAt: phase.handoffUpdatedAt,
18
53
  missingCompletionTaskIds: missingCompletionTasks.map((task) => task.id),
19
54
  missingCompletionTasks,
55
+ completenessVersion: HANDOFF_COMPLETENESS_AUDIT_VERSION,
56
+ maxContentChars: MAX_HANDOFF_CONTENT_CHARS,
57
+ completenessCategories: HANDOFF_COMPLETENESS_CATEGORIES,
58
+ existingCompletenessAudit: phase.handoffAudit,
20
59
  };
21
60
  }
22
61
  function nonEmpty(value, field) {
@@ -34,6 +73,74 @@ function appendSection(existing, section) {
34
73
  return existing;
35
74
  return existing.trim() ? `${existing.trim()}\n\n---\n${normalized}` : normalized;
36
75
  }
76
+ function isSubstantive(value) {
77
+ const normalized = value.trim();
78
+ if (normalized.length < 12)
79
+ return false;
80
+ return !/^(?:n\/?a|none|nothing|unknown|same as above|see (?:above|handoff|document)|not applicable|tbd)[.!]?$/i.test(normalized);
81
+ }
82
+ function stripRenderedCompletenessAudit(content) {
83
+ const start = content.indexOf(HANDOFF_AUDIT_START_MARKER);
84
+ if (start < 0)
85
+ return content.trim();
86
+ const end = content.indexOf(HANDOFF_AUDIT_END_MARKER, start);
87
+ if (end < 0)
88
+ return content.slice(0, start).trim();
89
+ return `${content.slice(0, start)}${content.slice(end + HANDOFF_AUDIT_END_MARKER.length)}`.trim();
90
+ }
91
+ export function handoffContentHash(content) {
92
+ return createHash("sha256").update(content).digest("hex");
93
+ }
94
+ export function validateHandoffCompletenessAudit(audit) {
95
+ const expectedIds = HANDOFF_COMPLETENESS_CATEGORIES.map((entry) => entry.id);
96
+ if (!audit || audit.version !== HANDOFF_COMPLETENESS_AUDIT_VERSION) {
97
+ throw new HandoffContractError("HANDOFF_COMPLETENESS_AUDIT_REQUIRED", `Handoff completeness audit version ${HANDOFF_COMPLETENESS_AUDIT_VERSION} is required.`, { requiredVersion: HANDOFF_COMPLETENESS_AUDIT_VERSION, missingCategories: expectedIds });
98
+ }
99
+ const byCategory = new Map();
100
+ const duplicates = [];
101
+ for (const entry of audit.entries) {
102
+ if (byCategory.has(entry.category))
103
+ duplicates.push(entry.category);
104
+ else
105
+ byCategory.set(entry.category, entry);
106
+ }
107
+ const missingCategories = expectedIds.filter((id) => !byCategory.has(id));
108
+ const unknownCategories = [...byCategory.keys()].filter((id) => !expectedIds.includes(id));
109
+ const invalidCategories = expectedIds.filter((id) => {
110
+ const entry = byCategory.get(id);
111
+ return entry ? !isSubstantive(entry.detail) : false;
112
+ });
113
+ if (missingCategories.length > 0 || unknownCategories.length > 0 || duplicates.length > 0 || invalidCategories.length > 0) {
114
+ throw new HandoffContractError("HANDOFF_COMPLETENESS_AUDIT_REQUIRED", "The handoff completeness audit is missing required categories or contains non-substantive entries.", { missingCategories, invalidCategories, unknownCategories, duplicateCategories: [...new Set(duplicates)] });
115
+ }
116
+ return expectedIds.map((id) => byCategory.get(id));
117
+ }
118
+ export function renderHandoffCompletenessAudit(audit) {
119
+ const entries = validateHandoffCompletenessAudit(audit);
120
+ const labels = new Map(HANDOFF_COMPLETENESS_CATEGORIES.map((entry) => [entry.id, entry.label]));
121
+ return [
122
+ HANDOFF_AUDIT_START_MARKER,
123
+ `## Operational completeness audit (v${HANDOFF_COMPLETENESS_AUDIT_VERSION})`,
124
+ "",
125
+ ...entries.flatMap((entry) => [
126
+ `### ${labels.get(entry.category) ?? entry.category}`,
127
+ `**Status:** ${entry.status}`,
128
+ entry.detail.trim(),
129
+ "",
130
+ ]),
131
+ HANDOFF_AUDIT_END_MARKER,
132
+ ].join("\n").trim();
133
+ }
134
+ export function renderVerifiedHandoffContent(content, audit) {
135
+ const base = stripRenderedCompletenessAudit(content);
136
+ validateCanonicalHandoffContent(base);
137
+ validateHandoffCompletenessAudit(audit);
138
+ const rendered = `${base}\n\n${renderHandoffCompletenessAudit(audit)}`.trim();
139
+ if (rendered.length > MAX_HANDOFF_CONTENT_CHARS) {
140
+ throw new HandoffContractError("HANDOFF_CONTENT_LIMIT_EXCEEDED", `Canonical handoff content is ${rendered.length} characters; the maximum is ${MAX_HANDOFF_CONTENT_CHARS}. Move extended detail to committed Markdown under .planner/docs/ and link it with a substantive explanation.`, { contentLength: rendered.length, maxContentChars: MAX_HANDOFF_CONTENT_CHARS });
141
+ }
142
+ return rendered;
143
+ }
37
144
  export function validateCanonicalHandoffContent(content) {
38
145
  const body = nonEmpty(content, "Handoff content");
39
146
  const required = [
@@ -53,7 +160,22 @@ export function validateCanonicalHandoffContent(content) {
53
160
  throw new Error(`Canonical handoff is missing required sections: ${missing.join(", ")}.`);
54
161
  }
55
162
  export function validateHandoffContextSync(phase, feature, input) {
56
- validateCanonicalHandoffContent(input.content);
163
+ renderVerifiedHandoffContent(input.content, input.completenessAudit);
164
+ const requestedDocuments = input.supportingDocuments ?? [];
165
+ const verifiedDocuments = input.verifiedSupportingDocuments ?? [];
166
+ if (requestedDocuments.length !== verifiedDocuments.length) {
167
+ throw new HandoffContractError("HANDOFF_SUPPORTING_DOCUMENT_INVALID", "Every supporting document must be validated by PlanStore before the handoff is written.", { requestedCount: requestedDocuments.length, verifiedCount: verifiedDocuments.length });
168
+ }
169
+ for (let index = 0; index < requestedDocuments.length; index += 1) {
170
+ const requested = requestedDocuments[index];
171
+ const verified = verifiedDocuments[index];
172
+ if (requested.path !== verified.path || !isSubstantive(requested.description) || requested.description.trim() !== verified.description) {
173
+ throw new HandoffContractError("HANDOFF_SUPPORTING_DOCUMENT_INVALID", `Supporting document ${requested.path || `(index ${index})`} is not valid or lacks a substantive description.`, { index, path: requested.path });
174
+ }
175
+ if (!input.content.includes(requested.path)) {
176
+ throw new HandoffContractError("HANDOFF_SUPPORTING_DOCUMENT_INVALID", `Canonical handoff content must link supporting document ${requested.path}.`, { index, path: requested.path });
177
+ }
178
+ }
57
179
  if (phase.status === "done" || phase.status === "canceled") {
58
180
  throw new Error(`Cannot write a handoff on ${phase.status} phase ${phase.id}; completed phases have no pending handoff.`);
59
181
  }
@@ -100,6 +222,8 @@ export function validateHandoffContextSync(phase, feature, input) {
100
222
  }
101
223
  export function applyHandoffContextSync(phase, feature, input, timestamp) {
102
224
  validateHandoffContextSync(phase, feature, input);
225
+ const handoffContent = renderVerifiedHandoffContent(input.content, input.completenessAudit);
226
+ const auditEntries = validateHandoffCompletenessAudit(input.completenessAudit);
103
227
  const nextPhase = structuredClone(phase);
104
228
  const nextFeature = structuredClone(feature);
105
229
  const updatedTaskIds = [];
@@ -141,8 +265,16 @@ export function applyHandoffContextSync(phase, feature, input, timestamp) {
141
265
  nextFeature.workDone = appendSection(nextFeature.workDone, featureUpdate.workDone);
142
266
  nextFeature.workRemaining = appendSection(nextFeature.workRemaining, featureUpdate.workRemaining);
143
267
  }
144
- nextPhase.handoff = input.content.trim();
268
+ nextPhase.handoff = handoffContent;
145
269
  nextPhase.handoffUpdatedAt = timestamp;
270
+ nextPhase.handoffAudit = {
271
+ version: HANDOFF_COMPLETENESS_AUDIT_VERSION,
272
+ entries: auditEntries,
273
+ supportingDocuments: input.verifiedSupportingDocuments ?? [],
274
+ contentHash: handoffContentHash(handoffContent),
275
+ contentLength: handoffContent.length,
276
+ verifiedAt: timestamp,
277
+ };
146
278
  nextPhase.handoffReadAt = "";
147
279
  nextPhase.updatedAt = timestamp;
148
280
  nextFeature.updatedAt = timestamp;
package/dist/index.d.ts CHANGED
@@ -4,14 +4,18 @@ export * from "./schema.js";
4
4
  export * from "./checklist.js";
5
5
  export * from "./recap.js";
6
6
  export * from "./planner-rules.js";
7
+ export * from "./planner-skill.js";
7
8
  export * from "./display-status.js";
8
9
  export * from "./task-context.js";
9
10
  export * from "./task-selection.js";
10
11
  export * from "./task-start-outcome.js";
11
12
  export * from "./read-tracking.js";
13
+ export * from "./payload-fallback.js";
12
14
  export * from "./handoff-context.js";
15
+ export * from "./project-context-migration.js";
16
+ export * from "./requirement-macro-tasks.js";
13
17
  export * from "./package-version.js";
14
- export { PlanStore, PlanStoreError, setWriteBusyHook, setWriteNotifyHook, migrateToUuids, migrateToGlobalSequence, withFeatureLock, type PhaseHandoffSummary, type OrphanPhaseSummary } from "./plan-store.js";
18
+ export { PlanStore, PlanStoreError, setWriteBusyHook, setWriteNotifyHook, migrateToUuids, migrateToGlobalSequence, withFeatureLock, type IdeaCreateInput, type IdeaUpdateInput, type IdeaPromotionTargetInput, type PhaseHandoffSummary, type OrphanPhaseSummary } from "./plan-store.js";
15
19
  export { PlanRenderer } from "./renderer.js";
16
20
  export { ExportService } from "./export-service.js";
17
21
  export type { CodebaseProfile, ResumeFocus, ActivityEntry, ActivityLog, AmbientFacts } from "./schema.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,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"}
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,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sBAAsB,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,cAAc,EAAE,uBAAuB,EAAE,eAAe,EAAE,KAAK,eAAe,EAAE,KAAK,eAAe,EAAE,KAAK,wBAAwB,EAAE,KAAK,mBAAmB,EAAE,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC1R,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
@@ -4,12 +4,16 @@ export * from "./schema.js";
4
4
  export * from "./checklist.js";
5
5
  export * from "./recap.js";
6
6
  export * from "./planner-rules.js";
7
+ export * from "./planner-skill.js";
7
8
  export * from "./display-status.js";
8
9
  export * from "./task-context.js";
9
10
  export * from "./task-selection.js";
10
11
  export * from "./task-start-outcome.js";
11
12
  export * from "./read-tracking.js";
13
+ export * from "./payload-fallback.js";
12
14
  export * from "./handoff-context.js";
15
+ export * from "./project-context-migration.js";
16
+ export * from "./requirement-macro-tasks.js";
13
17
  export * from "./package-version.js";
14
18
  export { PlanStore, PlanStoreError, setWriteBusyHook, setWriteNotifyHook, migrateToUuids, migrateToGlobalSequence, withFeatureLock } from "./plan-store.js";
15
19
  export { PlanRenderer } from "./renderer.js";
package/dist/naming.d.ts CHANGED
@@ -39,6 +39,8 @@ export declare function formatThreeDigitNumber(value: number): string;
39
39
  export declare function formatPhaseRef(phaseNumber: number, featureNumber?: number): string;
40
40
  /** Human-readable feature ref: `F00x`. Harness-agnostic. */
41
41
  export declare function formatFeatureRef(featureNumber: number): string;
42
+ /** Human-readable idea ref: `I00x`. Ideas use an independent global sequence. */
43
+ export declare function formatIdeaRef(ideaNumber: number): string;
42
44
  /** Find the parent feature's number for a phase (for P00x(F00x) composite refs). */
43
45
  export declare function featureNumberOfPhase(phase: {
44
46
  featureId?: string | null | undefined;
@@ -53,6 +55,7 @@ export declare function isLegacyPhaseId(phaseId: string): boolean;
53
55
  export declare function migratePhaseId(featureId: string, number: number, slug: string): string;
54
56
  export declare function createTaskId(): string;
55
57
  export declare function createRequirementId(): string;
58
+ export declare function createIdeaId(): string;
56
59
  export declare function createMacroTaskId(): string;
57
60
  export declare function createFeatureId(): string;
58
61
  export declare function createChecklistItemId(taskId: string, number: number, title: string): string;
@@ -1 +1 @@
1
- {"version":3,"file":"naming.d.ts","sourceRoot":"","sources":["../src/naming.ts"],"names":[],"mappings":"AAKA;iFACiF;AACjF,eAAO,MAAM,kBAAkB,qCAAqC,CAAC;AAErE,eAAO,MAAM,eAAe,IAAI,CAAC;AACjC,eAAO,MAAM,gBAAgB,QAAkB,CAAC;AAEhD,4EAA4E;AAC5E,eAAO,MAAM,YAAY,QAAoE,CAAC;AAE9F,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAEtD;AAED;;gEAEgE;AAChE,wBAAsB,sBAAsB,CAAC,CAAC,SAAS;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,EACnE,IAAI,EAAE,SAAS,GAAG,OAAO,EACzB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,GACnC,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAStD;AAGD;;;;;qCAKqC;AACrC,wBAAgB,aAAa,CAAC,QAAQ,GAAE,GAAG,CAAC,MAAM,CAAa,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CA2BtF;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAOnD;AAED;;;;8BAI8B;AAC9B,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,SAAK,EAAE,QAAQ,SAAa,GAAG,MAAM,CAGnF;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED;;iBAEiB;AACjB,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,CAGlF;AAED,4DAA4D;AAC5D,wBAAgB,gBAAgB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED,oFAAoF;AACpF,wBAAgB,oBAAoB,CAClC,KAAK,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAA;CAAE,EAChD,QAAQ,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EAAE,GACzC,MAAM,GAAG,SAAS,CAEpB;AAED,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,mFAAmF;AACnF,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAExD;AAED,0FAA0F;AAC1F,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAGtF;AAED,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C;AAED,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAE3F;AAED,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C"}
1
+ {"version":3,"file":"naming.d.ts","sourceRoot":"","sources":["../src/naming.ts"],"names":[],"mappings":"AAKA;iFACiF;AACjF,eAAO,MAAM,kBAAkB,qCAAqC,CAAC;AAErE,eAAO,MAAM,eAAe,IAAI,CAAC;AACjC,eAAO,MAAM,gBAAgB,QAAkB,CAAC;AAEhD,4EAA4E;AAC5E,eAAO,MAAM,YAAY,QAAoE,CAAC;AAE9F,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAEtD;AAED;;gEAEgE;AAChE,wBAAsB,sBAAsB,CAAC,CAAC,SAAS;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,EACnE,IAAI,EAAE,SAAS,GAAG,OAAO,EACzB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,GACnC,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAStD;AAGD;;;;;qCAKqC;AACrC,wBAAgB,aAAa,CAAC,QAAQ,GAAE,GAAG,CAAC,MAAM,CAAa,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CA2BtF;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAOnD;AAED;;;;8BAI8B;AAC9B,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,SAAK,EAAE,QAAQ,SAAa,GAAG,MAAM,CAGnF;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED;;iBAEiB;AACjB,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,CAGlF;AAED,4DAA4D;AAC5D,wBAAgB,gBAAgB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED,iFAAiF;AACjF,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAExD;AAED,oFAAoF;AACpF,wBAAgB,oBAAoB,CAClC,KAAK,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAA;CAAE,EAChD,QAAQ,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EAAE,GACzC,MAAM,GAAG,SAAS,CAEpB;AAED,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,mFAAmF;AACnF,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAExD;AAED,0FAA0F;AAC1F,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAGtF;AAED,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C;AAED,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAE3F;AAED,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C"}
package/dist/naming.js CHANGED
@@ -94,6 +94,10 @@ export function formatPhaseRef(phaseNumber, featureNumber) {
94
94
  export function formatFeatureRef(featureNumber) {
95
95
  return `F${formatThreeDigitNumber(featureNumber)}`;
96
96
  }
97
+ /** Human-readable idea ref: `I00x`. Ideas use an independent global sequence. */
98
+ export function formatIdeaRef(ideaNumber) {
99
+ return `I${formatThreeDigitNumber(ideaNumber)}`;
100
+ }
97
101
  /** Find the parent feature's number for a phase (for P00x(F00x) composite refs). */
98
102
  export function featureNumberOfPhase(phase, features) {
99
103
  return phase.featureId ? features.find((f) => f.id === phase.featureId)?.number : undefined;
@@ -116,6 +120,9 @@ export function createTaskId() {
116
120
  export function createRequirementId() {
117
121
  return randomUUID();
118
122
  }
123
+ export function createIdeaId() {
124
+ return randomUUID();
125
+ }
119
126
  export function createMacroTaskId() {
120
127
  return randomUUID();
121
128
  }
@@ -0,0 +1,38 @@
1
+ export type PlannerPayloadEntity = "project" | "feature" | "phase" | "task";
2
+ export type PlannerPayloadOperation = "update" | "discuss";
3
+ export type PlannerPayloadFailureCode = "NO_MUTABLE_FIELDS_RECEIVED" | "DESCRIPTION_MARKDOWN_FALLBACK_REQUIRED";
4
+ export interface DescriptionFallbackInput {
5
+ entityId?: string;
6
+ inputField: string;
7
+ storedField: string;
8
+ descriptionRefField: string;
9
+ }
10
+ export interface NoMutableFieldsReceivedInput {
11
+ entity: PlannerPayloadEntity;
12
+ ref: string;
13
+ operation: PlannerPayloadOperation;
14
+ mutableFields: readonly string[];
15
+ retryCommand: string;
16
+ readBackCommand?: string;
17
+ descriptionFallback?: DescriptionFallbackInput;
18
+ }
19
+ export interface NoMutableFieldsReceivedResult {
20
+ updated: false;
21
+ discussed?: false;
22
+ reason: "no-mutable-fields";
23
+ errorCode: PlannerPayloadFailureCode;
24
+ suspectedLongTextPayloadLoss: boolean;
25
+ entity: PlannerPayloadEntity;
26
+ ref: string;
27
+ operation: PlannerPayloadOperation;
28
+ mutableFields: string[];
29
+ fallbackDocPath?: string;
30
+ fallbackDescriptionTemplate?: string;
31
+ nextActions: string[];
32
+ message: string;
33
+ }
34
+ export declare function normalizeDescriptionRef(value: string | undefined): string | undefined;
35
+ export declare function isPlannerDescriptionRef(value: string): boolean;
36
+ export declare function suggestedDescriptionRefPath(entity: PlannerPayloadEntity, entityId?: string): string;
37
+ export declare function noMutableFieldsReceived(input: NoMutableFieldsReceivedInput): NoMutableFieldsReceivedResult;
38
+ //# sourceMappingURL=payload-fallback.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"payload-fallback.d.ts","sourceRoot":"","sources":["../src/payload-fallback.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,oBAAoB,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC;AAC5E,MAAM,MAAM,uBAAuB,GAAG,QAAQ,GAAG,SAAS,CAAC;AAC3D,MAAM,MAAM,yBAAyB,GAAG,4BAA4B,GAAG,wCAAwC,CAAC;AAEhH,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,4BAA4B;IAC3C,MAAM,EAAE,oBAAoB,CAAC;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,uBAAuB,CAAC;IACnC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,wBAAwB,CAAC;CAChD;AAED,MAAM,WAAW,6BAA6B;IAC5C,OAAO,EAAE,KAAK,CAAC;IACf,SAAS,CAAC,EAAE,KAAK,CAAC;IAClB,MAAM,EAAE,mBAAmB,CAAC;IAC5B,SAAS,EAAE,yBAAyB,CAAC;IACrC,4BAA4B,EAAE,OAAO,CAAC;IACtC,MAAM,EAAE,oBAAoB,CAAC;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,uBAAuB,CAAC;IACnC,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,2BAA2B,CAAC,EAAE,MAAM,CAAC;IACrC,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAGrF;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAO9D;AAED,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,oBAAoB,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAWnG;AAED,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,4BAA4B,GAClC,6BAA6B,CAgD/B"}
@@ -0,0 +1,73 @@
1
+ export function normalizeDescriptionRef(value) {
2
+ const trimmed = value?.trim();
3
+ return trimmed ? trimmed : undefined;
4
+ }
5
+ export function isPlannerDescriptionRef(value) {
6
+ if (!value.startsWith(".planner/docs/"))
7
+ return false;
8
+ if (value.includes("\\") || value.includes("\0"))
9
+ return false;
10
+ const parts = value.split("/");
11
+ if (parts.length < 4)
12
+ return false;
13
+ if (parts[0] !== ".planner" || parts[1] !== "docs")
14
+ return false;
15
+ return parts.slice(2).every((part) => part.length > 0 && part !== "." && part !== "..");
16
+ }
17
+ export function suggestedDescriptionRefPath(entity, entityId) {
18
+ switch (entity) {
19
+ case "project":
20
+ return ".planner/docs/project/description.md";
21
+ case "feature":
22
+ return `.planner/docs/features/${entityId ?? "feature"}.md`;
23
+ case "phase":
24
+ return `.planner/docs/phases/${entityId ?? "phase"}.md`;
25
+ case "task":
26
+ return `.planner/docs/tasks/${entityId ?? "task"}.md`;
27
+ }
28
+ }
29
+ export function noMutableFieldsReceived(input) {
30
+ const mutableFields = [...input.mutableFields];
31
+ const fallbackDocPath = input.descriptionFallback
32
+ ? suggestedDescriptionRefPath(input.entity, input.descriptionFallback.entityId)
33
+ : undefined;
34
+ const nextActions = input.descriptionFallback && fallbackDocPath
35
+ ? [
36
+ `Create a committed markdown file at ${fallbackDocPath} containing the full intended ${input.descriptionFallback.storedField}.`,
37
+ `Retry ${input.retryCommand} with a concise ${input.descriptionFallback.inputField} summary and ${input.descriptionFallback.descriptionRefField} set to ${fallbackDocPath}.`,
38
+ ...(input.readBackCommand
39
+ ? [`Read back ${input.readBackCommand} and confirm the summary plus ${input.descriptionFallback.descriptionRefField} survived.`]
40
+ : []),
41
+ "Continue only after the read-back confirms the markdown reference persisted.",
42
+ ]
43
+ : [
44
+ `Retry ${input.retryCommand} with at least one mutable field: ${mutableFields.join(", ")}.`,
45
+ ];
46
+ const fallbackDescriptionTemplate = fallbackDocPath
47
+ ? `Concise summary here. Full description is stored in ${fallbackDocPath}.`
48
+ : undefined;
49
+ const message = [
50
+ "Not updated — no mutable fields were received.",
51
+ "No planner data was changed.",
52
+ input.descriptionFallback
53
+ ? `If you attempted to send a long ${input.descriptionFallback.inputField}, it may have exceeded the tool payload limit before reaching the planner.`
54
+ : `Provide at least one mutable field for this ${input.operation} operation.`,
55
+ "Next required actions:",
56
+ ...nextActions.map((action, index) => `${index + 1}. ${action}`),
57
+ ].join("\n");
58
+ return {
59
+ updated: false,
60
+ ...(input.operation === "discuss" ? { discussed: false } : {}),
61
+ reason: "no-mutable-fields",
62
+ errorCode: input.descriptionFallback ? "DESCRIPTION_MARKDOWN_FALLBACK_REQUIRED" : "NO_MUTABLE_FIELDS_RECEIVED",
63
+ suspectedLongTextPayloadLoss: Boolean(input.descriptionFallback),
64
+ entity: input.entity,
65
+ ref: input.ref,
66
+ operation: input.operation,
67
+ mutableFields,
68
+ ...(fallbackDocPath ? { fallbackDocPath } : {}),
69
+ ...(fallbackDescriptionTemplate ? { fallbackDescriptionTemplate } : {}),
70
+ nextActions,
71
+ message,
72
+ };
73
+ }