@agent-plan/core 0.2.29 → 0.3.1

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 (92) hide show
  1. package/dist/accepted-decision-guard.d.ts +94 -0
  2. package/dist/accepted-decision-guard.d.ts.map +1 -0
  3. package/dist/accepted-decision-guard.js +110 -0
  4. package/dist/checklist.d.ts +28 -0
  5. package/dist/checklist.d.ts.map +1 -1
  6. package/dist/checklist.js +59 -0
  7. package/dist/feature-delete.d.ts +62 -0
  8. package/dist/feature-delete.d.ts.map +1 -0
  9. package/dist/feature-delete.js +49 -0
  10. package/dist/guard-decision.d.ts +128 -0
  11. package/dist/guard-decision.d.ts.map +1 -0
  12. package/dist/guard-decision.js +269 -0
  13. package/dist/guard-state.d.ts +14 -0
  14. package/dist/guard-state.d.ts.map +1 -0
  15. package/dist/guard-state.js +35 -0
  16. package/dist/handoff-context.d.ts +130 -1
  17. package/dist/handoff-context.d.ts.map +1 -1
  18. package/dist/handoff-context.js +167 -9
  19. package/dist/handoff-reply.d.ts +113 -0
  20. package/dist/handoff-reply.d.ts.map +1 -0
  21. package/dist/handoff-reply.js +279 -0
  22. package/dist/index.d.ts +18 -1
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +18 -1
  25. package/dist/load-reply.d.ts +63 -0
  26. package/dist/load-reply.d.ts.map +1 -0
  27. package/dist/load-reply.js +64 -0
  28. package/dist/mutation-reply.d.ts +105 -0
  29. package/dist/mutation-reply.d.ts.map +1 -0
  30. package/dist/mutation-reply.js +203 -0
  31. package/dist/naming.d.ts +1 -1
  32. package/dist/naming.d.ts.map +1 -1
  33. package/dist/naming.js +1 -1
  34. package/dist/on-hold.d.ts +55 -0
  35. package/dist/on-hold.d.ts.map +1 -0
  36. package/dist/on-hold.js +123 -0
  37. package/dist/package-version.d.ts +13 -0
  38. package/dist/package-version.d.ts.map +1 -1
  39. package/dist/package-version.js +32 -0
  40. package/dist/pagination.d.ts +19 -0
  41. package/dist/pagination.d.ts.map +1 -0
  42. package/dist/pagination.js +15 -0
  43. package/dist/payload-fallback.js +1 -1
  44. package/dist/plan-store.d.ts +141 -8
  45. package/dist/plan-store.d.ts.map +1 -1
  46. package/dist/plan-store.js +459 -87
  47. package/dist/project-context-migration.d.ts +5 -0
  48. package/dist/project-context-migration.d.ts.map +1 -1
  49. package/dist/project-context-migration.js +13 -0
  50. package/dist/project-context.d.ts +397 -0
  51. package/dist/project-context.d.ts.map +1 -0
  52. package/dist/project-context.js +294 -0
  53. package/dist/recap.d.ts.map +1 -1
  54. package/dist/recap.js +33 -0
  55. package/dist/recommend-reply.d.ts +51 -0
  56. package/dist/recommend-reply.d.ts.map +1 -0
  57. package/dist/recommend-reply.js +93 -0
  58. package/dist/refs.d.ts +16 -0
  59. package/dist/refs.d.ts.map +1 -1
  60. package/dist/refs.js +38 -0
  61. package/dist/renderer.d.ts.map +1 -1
  62. package/dist/schema.d.ts +7 -2
  63. package/dist/schema.d.ts.map +1 -1
  64. package/dist/schema.js +8 -3
  65. package/dist/stranded-phase.d.ts +73 -0
  66. package/dist/stranded-phase.d.ts.map +1 -0
  67. package/dist/stranded-phase.js +93 -0
  68. package/dist/task-completion-gate.d.ts +84 -0
  69. package/dist/task-completion-gate.d.ts.map +1 -0
  70. package/dist/task-completion-gate.js +72 -0
  71. package/dist/task-context.d.ts +1 -0
  72. package/dist/task-context.d.ts.map +1 -1
  73. package/dist/task-context.js +42 -14
  74. package/dist/task-lifecycle.d.ts +12 -0
  75. package/dist/task-lifecycle.d.ts.map +1 -0
  76. package/dist/task-lifecycle.js +23 -0
  77. package/dist/task-order-context.d.ts +72 -0
  78. package/dist/task-order-context.d.ts.map +1 -0
  79. package/dist/task-order-context.js +82 -0
  80. package/dist/task-selection.d.ts +4 -1
  81. package/dist/task-selection.d.ts.map +1 -1
  82. package/dist/task-selection.js +36 -14
  83. package/dist/task-start-outcome.d.ts +26 -0
  84. package/dist/task-start-outcome.d.ts.map +1 -1
  85. package/dist/task-start-outcome.js +23 -0
  86. package/dist/text-bounds.d.ts +32 -0
  87. package/dist/text-bounds.d.ts.map +1 -0
  88. package/dist/text-bounds.js +43 -0
  89. package/dist/write-coordination.d.ts +2 -2
  90. package/dist/write-coordination.js +2 -2
  91. package/package.json +1 -1
  92. package/planner-skill.md +30 -12
@@ -0,0 +1,279 @@
1
+ import { MAX_HANDOFF_CONTENT_CHARS, handoffContentHash, } from "./handoff-context.js";
2
+ import { boundedContentForTransport } from "./text-bounds.js";
3
+ /**
4
+ * Render a HandoffContractError (handoff refresh/prepare denial) as a
5
+ * text/structured pair. Both adapters carried an identical copy; kept here
6
+ * so the message and the `errorCode`/details shape can never drift between
7
+ * MCP and Pi. Each adapter still owns its own envelope (`isError` +
8
+ * `structuredContent` for MCP, `details` for Pi) — see AGENTS.md rule 4.
9
+ */
10
+ export function handoffContractFailureReply(error, action = "refresh") {
11
+ const recovery = typeof error.details.recovery === "string" ? ` Recovery: ${error.details.recovery}` : "";
12
+ return {
13
+ text: `❌ Handoff ${action} denied [${error.code}]: ${error.message}${recovery}`,
14
+ structured: { errorCode: error.code, ...error.details },
15
+ };
16
+ }
17
+ /** Bound raw handoff content to the absolute compatibility ceiling for
18
+ * transport. Legacy or externally-written content can exceed the ceiling;
19
+ * everything produced through the normal write path already respects it.
20
+ * Cuts at a safe boundary (paragraph, then line, then word — see
21
+ * boundedContentForTransport / truncateAtSafeBoundary in handoff-context.ts)
22
+ * rather than an arbitrary character offset, so the visible remainder never
23
+ * ends mid-word. */
24
+ export function boundedHandoffForTransport(content) {
25
+ const suffix = "\n\n[Legacy handoff truncated for transport safety. Move extended detail to a linked file under .planner/docs/ and refresh the handoff.]";
26
+ if (content.length <= MAX_HANDOFF_CONTENT_CHARS)
27
+ return { content, fullLength: content.length, truncated: false };
28
+ const bounded = boundedContentForTransport(content, Math.max(0, MAX_HANDOFF_CONTENT_CHARS - suffix.length));
29
+ return { content: `${bounded.content}${suffix}`, fullLength: content.length, truncated: true };
30
+ }
31
+ /**
32
+ * Render the existing handoff's auto-externalized documents (see
33
+ * HandoffExternalizedDocumentAudit) for the prepare text channel. Shares one
34
+ * budget across every document rather than bounding each independently to
35
+ * MAX_HANDOFF_CONTENT_CHARS, so several documents from successive rewrites
36
+ * cannot each spend the full ceiling — the reporting phase's own P082 capsule
37
+ * carried two linked documents at once, and a prior capsule's externalized
38
+ * document can by itself already be as large as the ceiling (a large draft
39
+ * is exactly what got externalized). Every document is still named — path,
40
+ * description, and heading table of contents — even when its content does
41
+ * not fit, so "elided" never again means "invisible": inlining degrades to
42
+ * naming, it never degrades to silence.
43
+ */
44
+ function renderExternalizedHandoffDocuments(documents) {
45
+ let remaining = MAX_HANDOFF_CONTENT_CHARS;
46
+ const blocks = [];
47
+ const structured = [];
48
+ for (const document of documents) {
49
+ const headingsNote = document.headings.length > 0 ? ` (sections: ${document.headings.join(", ")})` : "";
50
+ const header = `- ${document.path} — ${document.description}${headingsNote}`;
51
+ if (document.missing) {
52
+ blocks.push(`${header}\n [Not found on disk; its content is unavailable. Treat any facts it carried as unverified until confirmed another way.]`);
53
+ structured.push({ path: document.path, headings: document.headings, contentLength: document.contentLength, missing: true, inlined: false, truncated: false });
54
+ continue;
55
+ }
56
+ if (remaining <= 0) {
57
+ blocks.push(`${header}\n [Not inlined: the reconciliation budget for externalized detail is exhausted. Read this document directly before drafting.]`);
58
+ structured.push({ path: document.path, headings: document.headings, contentLength: document.contentLength, missing: false, inlined: false, truncated: false });
59
+ continue;
60
+ }
61
+ const bounded = boundedContentForTransport(document.content ?? "", remaining);
62
+ remaining -= bounded.content.length;
63
+ const continuation = bounded.truncated
64
+ ? "\n\n[Not fully inlined: remaining detail exceeds the reconciliation budget. Read this document directly for the rest.]"
65
+ : "";
66
+ blocks.push(`${header}\n${bounded.content}${continuation}`);
67
+ structured.push({ path: document.path, headings: document.headings, contentLength: document.contentLength, missing: false, inlined: true, truncated: bounded.truncated });
68
+ }
69
+ return { text: blocks.join("\n\n"), structured };
70
+ }
71
+ /**
72
+ * Transport shape of the phase work map. `entries` is the machine-readable
73
+ * twin of the rendered `content` — the same siblings spelled as JSON — and
74
+ * no caller reads it off a reply, so only the counts travel. Pass
75
+ * `includeContent` for the reply that renders the map in no other channel.
76
+ */
77
+ function workMapForTransport(map, includeContent) {
78
+ return {
79
+ ...(includeContent ? { content: map.content } : {}),
80
+ total: map.total,
81
+ truncated: map.truncated,
82
+ maxChars: map.maxChars,
83
+ };
84
+ }
85
+ /**
86
+ * Transport shape of the persisted audit. `entries`, `coldStartInventory`
87
+ * and `readBackSourceReviews` are planner-owned legacy evidence that agents
88
+ * are told not to reproduce (P100(F021)/T396) and that nothing reads back
89
+ * off a reply; only the verification facts travel.
90
+ */
91
+ function handoffAuditForTransport(audit) {
92
+ if (!audit)
93
+ return null;
94
+ return {
95
+ version: audit.version,
96
+ contentHash: audit.contentHash,
97
+ contentLength: audit.contentLength,
98
+ verifiedAt: audit.verifiedAt,
99
+ resumeReadyAt: audit.resumeReadyAt,
100
+ supportingDocuments: audit.supportingDocuments,
101
+ };
102
+ }
103
+ /**
104
+ * Build the reply for `planner-handoff-show` / `handoff_show`, covering the
105
+ * empty, archived, and active branches through one shared shape so no
106
+ * surface keeps its own construction.
107
+ *
108
+ * Placement: the resume capsule body is prose meant to be read, and every
109
+ * existing consumer reads it from `text` (never from `structured`), so
110
+ * `text` is its one home; `structured` carries only `fullLength`/
111
+ * `truncated` flags plus the identifiers, hash, and verification flags a
112
+ * structuredContent-only host needs to drive the candidate-then-verify
113
+ * contract (call verify with the right hash) without needing the prose
114
+ * itself.
115
+ */
116
+ export function buildHandoffShowReply(input) {
117
+ if (input.kind === "empty") {
118
+ return {
119
+ text: `No handoff set on ${input.phaseRef}.`,
120
+ structured: {
121
+ phaseRef: input.phaseRef,
122
+ phaseId: input.phaseId,
123
+ content: "",
124
+ empty: true,
125
+ resumeReady: false,
126
+ handoffAudit: handoffAuditForTransport(input.handoffAudit),
127
+ },
128
+ };
129
+ }
130
+ if (input.kind === "archived") {
131
+ const bounded = boundedHandoffForTransport(input.content);
132
+ const supportingDocuments = input.handoffAudit?.supportingDocuments ?? [];
133
+ const documentLines = supportingDocuments.map((document) => `- ${document.path} — ${document.description}`);
134
+ return {
135
+ text: [
136
+ `Archived terminal-phase handoff for ${input.phaseRef} (${input.archiveReason}; archived ${input.archivedAt})`,
137
+ ...(documentLines.length ? ["Supporting documents:", ...documentLines] : []),
138
+ "",
139
+ bounded.content,
140
+ ].join("\n"),
141
+ structured: {
142
+ phaseRef: input.phaseRef,
143
+ phaseId: input.phaseId,
144
+ active: false,
145
+ archived: true,
146
+ archiveReason: input.archiveReason,
147
+ archivedAt: input.archivedAt,
148
+ archiveFile: input.archiveFile,
149
+ fullLength: bounded.fullLength,
150
+ truncated: bounded.truncated,
151
+ supportingDocuments,
152
+ empty: false,
153
+ resumeReady: false,
154
+ handoffAudit: handoffAuditForTransport(input.handoffAudit),
155
+ },
156
+ };
157
+ }
158
+ const { phase, phaseRef, phaseWorkMap } = input;
159
+ const bounded = boundedHandoffForTransport(phase.handoff);
160
+ const contentHash = handoffContentHash(phase.handoff);
161
+ const persistenceVerified = Boolean(phase.handoffAudit
162
+ && phase.handoffAudit.contentHash === contentHash
163
+ && phase.handoffAudit.contentLength === phase.handoff.length);
164
+ const resumeReady = persistenceVerified && Boolean(phase.handoffAudit?.resumeReadyAt);
165
+ const status = resumeReady
166
+ ? "Resume-ready: persisted compact capsule read-back completed."
167
+ : "NOT resume-ready: after reading this persisted capsule, call planner-handoff-verify with its contentHash. The planner derives legacy evidence from persisted state; rewrite only if the capsule itself omits resume-critical context.";
168
+ return {
169
+ text: `Handoff for ${phaseRef}\n${status}\nContent hash: ${contentHash}\n\n${phaseWorkMap.content}\n\nBefore proposing new work, reread the canonical phase and relevant sibling task full view; do not duplicate an already-owned capability.\n\n${bounded.content}`,
170
+ structured: {
171
+ phaseRef,
172
+ phaseId: phase.id,
173
+ // The rendered map is already in `text`, so only the counts travel.
174
+ phaseWorkMap: workMapForTransport(phaseWorkMap, false),
175
+ fullLength: bounded.fullLength,
176
+ truncated: bounded.truncated,
177
+ contentHash,
178
+ persistenceVerified,
179
+ resumeReady,
180
+ verificationRequired: !resumeReady,
181
+ handoffAudit: handoffAuditForTransport(phase.handoffAudit),
182
+ },
183
+ };
184
+ }
185
+ /** Single source of truth for the prepare-reply evidence-contract sentence,
186
+ * previously hardcoded identically in both adapters. */
187
+ export const HANDOFF_PREPARE_EVIDENCE_CONTRACT = "Planner-owned completeness and cold-start evidence is derived from persisted state; no category inventory is required from the agent.";
188
+ /**
189
+ * Build the reply for `planner-handoff-prepare` / `handoff_prepare`.
190
+ *
191
+ * Placement: `draftTemplate` has no consumer in `text` (only the intro line
192
+ * pointing at it is read there) and every existing consumer reads it from
193
+ * `structured`, so `structured` is its one home; `text` gets a pointer
194
+ * instead of a second copy. The existing active handoff being reconciled is
195
+ * the opposite: nothing reads it from `structured`, so it stays prose in
196
+ * `text` only, bounded for transport, with `structured` carrying just its
197
+ * length/truncated flags. `missingCompletionTasks` duplicates the same
198
+ * titles already rendered into `text`; `structured` keeps only the task ids
199
+ * needed to address `taskUpdates`. The existing handoff's auto-externalized
200
+ * documents follow the same rule as the existing handoff itself: their
201
+ * bodies are prose for `text` (see renderExternalizedHandoffDocuments),
202
+ * `structured` keeps only path/headings/size/inlined/truncated per document
203
+ * (existingHandoffExternalizedDocuments) — see P104(F005)/T415's accepted
204
+ * decision for why inlining (budget permitting) was chosen over a
205
+ * separate-field or names-only reply.
206
+ */
207
+ export function buildHandoffPrepareReply(input) {
208
+ const { phaseRef, audit } = input;
209
+ const { completenessCategories: _completenessCategories, coldStartSourceReviews: _coldStartSourceReviews, coldStartInventoryCategories: _coldStartInventoryCategories, handoff, missingCompletionTasks,
210
+ // Guidance is instruction the agent reads; the text channel renders it,
211
+ // so it must not travel again in the structured payload.
212
+ supportingDocumentsGuidance: _supportingDocumentsGuidance,
213
+ // Raw document bodies; never spread as-is into structured (see below —
214
+ // content stays text-only, structured keeps only the small facts).
215
+ externalizedHandoffDocuments, ...structuredAudit } = audit;
216
+ const missingLines = missingCompletionTasks
217
+ .map((task) => `- T${String(task.number).padStart(3, "0")} — ${task.title}`)
218
+ .join("\n") || "- None";
219
+ const existingBounded = boundedHandoffForTransport(handoff);
220
+ const existingText = existingBounded.content.trim() || "(none)";
221
+ const externalized = renderExternalizedHandoffDocuments(externalizedHandoffDocuments);
222
+ const text = [
223
+ `Handoff preparation for ${phaseRef}`,
224
+ `Base handoffUpdatedAt: ${audit.handoffUpdatedAt || "(empty)"}`,
225
+ "Required human inputs before drafting:",
226
+ ...audit.requiredHumanInputs.map((requiredInput) => `- ${requiredInput.id} — ${requiredInput.description}`),
227
+ "Planner-generated metadata (do not add these to Markdown): Created at, Updated at, Reason.",
228
+ "The exact drafting scaffold is provided in the structured result's draftTemplate field; replace every angle-bracket placeholder and retain every heading.",
229
+ "",
230
+ "Done tasks missing durable completion/verification evidence:",
231
+ missingLines,
232
+ "",
233
+ "Compact handoff contract: include only the exact focus/resume point, current or partial state, constraints, blockers, decisions, verification, and ordered next actions needed by the next agent.",
234
+ "No Markdown heading is mandatory: concise free-form resume prose is accepted. Use headings only when they make the capsule clearer.",
235
+ "Completeness audit and cold-start evidence are planner-owned metadata; do not copy their categories or source reviews into Markdown.",
236
+ `Inline target: ${audit.targetContentChars} characters; absolute compatibility ceiling: ${audit.maxContentChars}. Extended detail is externalized automatically when needed.`,
237
+ `Supporting documents: ${audit.supportingDocumentsGuidance}`,
238
+ "",
239
+ "Existing active handoff (reconcile all still-relevant content):",
240
+ existingText,
241
+ // Content this same active handoff previously moved out automatically.
242
+ // Reconciling "the existing handoff" means reconciling this too — it is
243
+ // not optional background reading, it is the part most likely to hold a
244
+ // fact no task holds (see AGENTS.md rule 4: this belongs here once, not
245
+ // rediscovered per adapter).
246
+ ...(externalizedHandoffDocuments.length > 0
247
+ ? [
248
+ "",
249
+ "Externalized detail from the existing handoff (auto-moved out when the capsule exceeded the inline target; reconcile before drafting — this is part of \"the existing handoff\", not optional background):",
250
+ externalized.text,
251
+ ]
252
+ : []),
253
+ ...(audit.priorSectionHeadings.length > 0
254
+ ? [
255
+ "",
256
+ `Prior sections to account for: ${audit.priorSectionHeadings.join(", ")}. Any of these missing as a "##" heading from the written content will be refused (HANDOFF_SECTION_RECONCILIATION_REQUIRED) unless you also submit sectionDispositions naming what happened to it (dropped, superseded, or folded into another section).`,
257
+ ]
258
+ : []),
259
+ ].join("\n");
260
+ return {
261
+ text,
262
+ structured: {
263
+ phaseRef,
264
+ ...structuredAudit,
265
+ // Prepare renders the map in no text channel, so it keeps `content`
266
+ // here — but not the JSON twin of the same siblings.
267
+ phaseWorkMap: workMapForTransport(structuredAudit.phaseWorkMap, true),
268
+ existingCompletenessAudit: handoffAuditForTransport(structuredAudit.existingCompletenessAudit),
269
+ existingHandoffLength: existingBounded.fullLength,
270
+ existingHandoffTruncated: existingBounded.truncated,
271
+ // Bodies are text-only (see externalized.text above); structured keeps
272
+ // only the facts a structuredContent-only host needs to know more
273
+ // exists than it can see: path, headings, size, and whether this call
274
+ // inlined it.
275
+ existingHandoffExternalizedDocuments: externalized.structured,
276
+ evidenceContract: HANDOFF_PREPARE_EVIDENCE_CONTRACT,
277
+ },
278
+ };
279
+ }
package/dist/index.d.ts CHANGED
@@ -1,5 +1,8 @@
1
1
  export * from "./naming.js";
2
2
  export * from "./refs.js";
3
+ export * from "./render-utils.js";
4
+ export * from "./pagination.js";
5
+ export * from "./task-lifecycle.js";
3
6
  export * from "./schema.js";
4
7
  export * from "./checklist.js";
5
8
  export * from "./recap.js";
@@ -7,18 +10,32 @@ export * from "./planner-rules.js";
7
10
  export * from "./planner-skill.js";
8
11
  export * from "./display-status.js";
9
12
  export * from "./description-freshness.js";
13
+ export * from "./text-bounds.js";
10
14
  export * from "./task-context.js";
11
15
  export * from "./task-selection.js";
12
16
  export * from "./task-start-outcome.js";
17
+ export * from "./task-order-context.js";
18
+ export * from "./task-completion-gate.js";
19
+ export * from "./stranded-phase.js";
13
20
  export * from "./read-tracking.js";
14
21
  export * from "./payload-fallback.js";
15
22
  export * from "./handoff-context.js";
23
+ export * from "./handoff-reply.js";
24
+ export * from "./mutation-reply.js";
25
+ export * from "./recommend-reply.js";
26
+ export * from "./feature-delete.js";
27
+ export * from "./accepted-decision-guard.js";
16
28
  export * from "./project-context-migration.js";
29
+ export * from "./project-context.js";
30
+ export * from "./load-reply.js";
31
+ export * from "./on-hold.js";
17
32
  export * from "./requirement-macro-tasks.js";
18
33
  export * from "./package-version.js";
19
34
  export * from "./runtime-diagnostics.js";
20
35
  export * from "./write-coordination.js";
21
- export { PlanStore, PlanStoreError, PlanStaleWriteError, PlanUnsupportedAllocationKindError, assertPlannerRevision, setWriteBusyHook, setWriteNotifyHook, migrateToUuids, migrateToGlobalSequence, withFeatureLock, type IdeaCreateInput, type IdeaUpdateInput, type IdeaPromotionTargetInput, type AcceptedDecisionOwner, type AcceptedDecisionCreateInput, type AcceptedDecisionUpdateInput, type PhaseHandoffSummary, type OrphanPhaseSummary } from "./plan-store.js";
36
+ export * from "./guard-decision.js";
37
+ export * from "./guard-state.js";
38
+ export { PlanStore, PlanStoreError, PlanStaleWriteError, PlanUnsupportedAllocationKindError, assertPlannerRevision, setWriteBusyHook, setWriteNotifyHook, migrateToUuids, migrateToGlobalSequence, withFeatureLock, nowISO, type IdeaCreateInput, type IdeaUpdateInput, type IdeaPromotionTargetInput, type AcceptedDecisionOwner, type AcceptedDecisionCreateInput, type AcceptedDecisionUpdateInput, type RecordProjectContextReadInput, type RecordProjectContextReadResult, type PhaseHandoffSummary, type OrphanPhaseSummary } from "./plan-store.js";
22
39
  export { PlanRenderer } from "./renderer.js";
23
40
  export { ExportService } from "./export-service.js";
24
41
  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,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,4BAA4B,CAAC;AAC3C,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,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,mBAAmB,EAAE,kCAAkC,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,cAAc,EAAE,uBAAuB,EAAE,eAAe,EAAE,KAAK,eAAe,EAAE,KAAK,eAAe,EAAE,KAAK,wBAAwB,EAAE,KAAK,qBAAqB,EAAE,KAAK,2BAA2B,EAAE,KAAK,2BAA2B,EAAE,KAAK,mBAAmB,EAAE,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC1c,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,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC;AACpC,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,4BAA4B,CAAC;AAC3C,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,mBAAmB,EAAE,kCAAkC,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,cAAc,EAAE,uBAAuB,EAAE,eAAe,EAAE,MAAM,EAAE,KAAK,eAAe,EAAE,KAAK,eAAe,EAAE,KAAK,wBAAwB,EAAE,KAAK,qBAAqB,EAAE,KAAK,2BAA2B,EAAE,KAAK,2BAA2B,EAAE,KAAK,6BAA6B,EAAE,KAAK,8BAA8B,EAAE,KAAK,mBAAmB,EAAE,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC3hB,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
@@ -1,5 +1,8 @@
1
1
  export * from "./naming.js";
2
2
  export * from "./refs.js";
3
+ export * from "./render-utils.js";
4
+ export * from "./pagination.js";
5
+ export * from "./task-lifecycle.js";
3
6
  export * from "./schema.js";
4
7
  export * from "./checklist.js";
5
8
  export * from "./recap.js";
@@ -7,17 +10,31 @@ export * from "./planner-rules.js";
7
10
  export * from "./planner-skill.js";
8
11
  export * from "./display-status.js";
9
12
  export * from "./description-freshness.js";
13
+ export * from "./text-bounds.js";
10
14
  export * from "./task-context.js";
11
15
  export * from "./task-selection.js";
12
16
  export * from "./task-start-outcome.js";
17
+ export * from "./task-order-context.js";
18
+ export * from "./task-completion-gate.js";
19
+ export * from "./stranded-phase.js";
13
20
  export * from "./read-tracking.js";
14
21
  export * from "./payload-fallback.js";
15
22
  export * from "./handoff-context.js";
23
+ export * from "./handoff-reply.js";
24
+ export * from "./mutation-reply.js";
25
+ export * from "./recommend-reply.js";
26
+ export * from "./feature-delete.js";
27
+ export * from "./accepted-decision-guard.js";
16
28
  export * from "./project-context-migration.js";
29
+ export * from "./project-context.js";
30
+ export * from "./load-reply.js";
31
+ export * from "./on-hold.js";
17
32
  export * from "./requirement-macro-tasks.js";
18
33
  export * from "./package-version.js";
19
34
  export * from "./runtime-diagnostics.js";
20
35
  export * from "./write-coordination.js";
21
- export { PlanStore, PlanStoreError, PlanStaleWriteError, PlanUnsupportedAllocationKindError, assertPlannerRevision, setWriteBusyHook, setWriteNotifyHook, migrateToUuids, migrateToGlobalSequence, withFeatureLock } from "./plan-store.js";
36
+ export * from "./guard-decision.js";
37
+ export * from "./guard-state.js";
38
+ export { PlanStore, PlanStoreError, PlanStaleWriteError, PlanUnsupportedAllocationKindError, assertPlannerRevision, setWriteBusyHook, setWriteNotifyHook, migrateToUuids, migrateToGlobalSequence, withFeatureLock, nowISO } from "./plan-store.js";
22
39
  export { PlanRenderer } from "./renderer.js";
23
40
  export { ExportService } from "./export-service.js";
@@ -0,0 +1,63 @@
1
+ import type { ProjectContextReply } from "./project-context.js";
2
+ import type { PlanWorkspace } from "./schema.js";
3
+ /**
4
+ * Reply shaping for an explicit planner load, shared by every adapter
5
+ * (MCP planner-load, Pi's planner-load tool and /planner load command).
6
+ *
7
+ * Every piece is sent once, in one text the agent reads top to bottom: the
8
+ * recap to show the user, then the agent-only context. `structured` carries
9
+ * only status fields; hosts that show the agent only structured content
10
+ * still get the text because the MCP server folds it in.
11
+ */
12
+ /** How the planner operating guide reaches the agent on this load. */
13
+ export type PlannerGuideDelivery =
14
+ /** The guide body is included (a host with no other way to deliver it). */
15
+ {
16
+ mode: "include";
17
+ content: string;
18
+ customized: boolean;
19
+ message: string;
20
+ }
21
+ /** The host already delivers the guide (e.g. Claude Code's /planner
22
+ * command); send only where it lives, never the body again. */
23
+ | {
24
+ mode: "pointer";
25
+ path: string;
26
+ customized: boolean;
27
+ message: string;
28
+ };
29
+ export interface PlannerLoadReplyInput {
30
+ recap: string;
31
+ projectContext: ProjectContextReply;
32
+ /** Accepted Decisions below project scope (feature/phase/task). Project
33
+ * decisions are already inside the project context. */
34
+ scopedDecisions?: {
35
+ content: string;
36
+ total: number;
37
+ truncated: boolean;
38
+ };
39
+ plannerGuide: PlannerGuideDelivery;
40
+ }
41
+ export interface PlannerLoadReply {
42
+ text: string;
43
+ structured: Record<string, unknown>;
44
+ }
45
+ export declare const PLANNER_LOAD_RECAP_HEADING = "## Recap \u2014 show this to the user verbatim";
46
+ export declare const PLANNER_LOAD_AGENT_HEADING = "## Agent-only context \u2014 read and keep it; never quote it in the recap";
47
+ /** Split a load reply's text back into the recap the user sees and the
48
+ * agent-only context. Any client (or test) that must show only the recap
49
+ * uses this instead of guessing at the layout. */
50
+ export declare function splitPlannerLoadText(text: string): {
51
+ recap: string;
52
+ agentContext: string;
53
+ };
54
+ export declare function buildPlannerLoadReply(input: PlannerLoadReplyInput): PlannerLoadReply;
55
+ /** Accepted Decisions owned by features, phases and tasks, bounded for a
56
+ * load reply. Project decisions are left out: the project context already
57
+ * carries them. */
58
+ export declare function buildScopedDecisionContext(plan: PlanWorkspace): {
59
+ content: string;
60
+ total: number;
61
+ truncated: boolean;
62
+ };
63
+ //# sourceMappingURL=load-reply.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load-reply.d.ts","sourceRoot":"","sources":["../src/load-reply.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAChE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIjD;;;;;;;;GAQG;AAEH,sEAAsE;AACtE,MAAM,MAAM,oBAAoB;AAC9B,2EAA2E;AACzE;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE;AAC5E;+DAC+D;GAC7D;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5E,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,mBAAmB,CAAC;IACpC;2DACuD;IACvD,eAAe,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC;IACzE,YAAY,EAAE,oBAAoB,CAAC;CACpC;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAED,eAAO,MAAM,0BAA0B,mDAA8C,CAAC;AACtF,eAAO,MAAM,0BAA0B,+EAA0E,CAAC;AAElH;;kDAEkD;AAClD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAK1F;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,qBAAqB,GAAG,gBAAgB,CAmCpF;AAED;;mBAEmB;AACnB,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,aAAa,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAYtH"}
@@ -0,0 +1,64 @@
1
+ import { featureNumberOfPhase, formatFeatureRef, formatPhaseRef } from "./naming.js";
2
+ import { buildBoundedAcceptedDecisionContext } from "./task-context.js";
3
+ export const PLANNER_LOAD_RECAP_HEADING = "## Recap — show this to the user verbatim";
4
+ export const PLANNER_LOAD_AGENT_HEADING = "## Agent-only context — read and keep it; never quote it in the recap";
5
+ /** Split a load reply's text back into the recap the user sees and the
6
+ * agent-only context. Any client (or test) that must show only the recap
7
+ * uses this instead of guessing at the layout. */
8
+ export function splitPlannerLoadText(text) {
9
+ const agentAt = text.indexOf(PLANNER_LOAD_AGENT_HEADING);
10
+ const recapStart = text.startsWith(PLANNER_LOAD_RECAP_HEADING) ? PLANNER_LOAD_RECAP_HEADING.length : 0;
11
+ if (agentAt < 0)
12
+ return { recap: text.slice(recapStart).trim(), agentContext: "" };
13
+ return { recap: text.slice(recapStart, agentAt).trim(), agentContext: text.slice(agentAt + PLANNER_LOAD_AGENT_HEADING.length).trim() };
14
+ }
15
+ export function buildPlannerLoadReply(input) {
16
+ const guide = input.plannerGuide;
17
+ const guideBlock = guide.mode === "include"
18
+ ? ["### Agent Plan operating guide", guide.customized ? guide.message : "", guide.content].filter(Boolean).join("\n\n")
19
+ : [
20
+ "### Agent Plan operating guide",
21
+ `Follow the Agent Plan operating guide. If it is not already in this conversation (the /planner command includes it), read ${guide.path}.`,
22
+ guide.customized ? guide.message : "",
23
+ ].filter(Boolean).join("\n");
24
+ const blocks = [
25
+ PLANNER_LOAD_RECAP_HEADING,
26
+ input.recap,
27
+ PLANNER_LOAD_AGENT_HEADING,
28
+ "### Project context",
29
+ input.projectContext.text,
30
+ ];
31
+ if (input.scopedDecisions && input.scopedDecisions.total > 0) {
32
+ blocks.push("### Accepted decisions for features, phases and tasks", input.scopedDecisions.content);
33
+ }
34
+ blocks.push(guideBlock);
35
+ return {
36
+ text: blocks.join("\n\n"),
37
+ structured: {
38
+ loaded: true,
39
+ projectContext: input.projectContext.structured,
40
+ plannerGuide: guide.mode === "include"
41
+ ? { mode: "include", customized: guide.customized }
42
+ : { mode: "pointer", path: guide.path, customized: guide.customized },
43
+ scopedDecisions: input.scopedDecisions
44
+ ? { total: input.scopedDecisions.total, truncated: input.scopedDecisions.truncated }
45
+ : { total: 0, truncated: false },
46
+ },
47
+ };
48
+ }
49
+ /** Accepted Decisions owned by features, phases and tasks, bounded for a
50
+ * load reply. Project decisions are left out: the project context already
51
+ * carries them. */
52
+ export function buildScopedDecisionContext(plan) {
53
+ const features = plan.features.features;
54
+ const phaseRef = (phase) => formatPhaseRef(phase.number, featureNumberOfPhase(phase, features));
55
+ const { content, total, truncated } = buildBoundedAcceptedDecisionContext([
56
+ ...features.map((feature) => ({ scope: `feature ${formatFeatureRef(feature.number)}`, decisions: feature.acceptedDecisions })),
57
+ ...plan.phases.map((phase) => ({ scope: `phase ${phaseRef(phase)}`, decisions: phase.acceptedDecisions })),
58
+ ...plan.phases.flatMap((phase) => phase.tasks.map((task) => ({
59
+ scope: `task ${phaseRef(phase)}/T${String(task.number).padStart(3, "0")}`,
60
+ decisions: task.acceptedDecisions,
61
+ }))),
62
+ ]);
63
+ return { content, total, truncated };
64
+ }
@@ -0,0 +1,105 @@
1
+ import type { PlannerPayloadEntity, PlannerPayloadOperation } from "./payload-fallback.js";
2
+ /**
3
+ * Per-field echo budget. A changed field is worth showing back so the caller
4
+ * can confirm what landed without a second call; a changed field the size of
5
+ * a task description is not. 2,000 characters is about three screens — long
6
+ * enough to read a title, a status, a checklist or a short note whole, short
7
+ * enough that echoing a full description is impossible.
8
+ */
9
+ export declare const MUTATION_ECHO_MAX_FIELD_CHARS = 2000;
10
+ /**
11
+ * Ceiling for the whole structured payload of a mutation reply. Chosen to
12
+ * match MAX_PHASE_WORK_MAP_CHARS and MAX_ACCEPTED_DECISION_CONTEXT_CHARS so
13
+ * an agent has one number in mind for planner payloads rather than four.
14
+ * When the assembled payload exceeds it, echoed values are dropped to names
15
+ * (see `boundMutationEcho`) — the caller still learns exactly which fields
16
+ * changed, which is the part it cannot get anywhere else.
17
+ */
18
+ export declare const MUTATION_REPLY_MAX_CHARS = 8000;
19
+ /**
20
+ * The long-text size a planner tool accepts in one call, stated up front so
21
+ * a caller does not discover it by being rejected. This is not a limit the
22
+ * planner imposes for its own sake: a long `description` can be dropped by
23
+ * the transport before it ever reaches the planner, which arrives here as
24
+ * "no mutable fields received" and is why DESCRIPTION_MARKDOWN_FALLBACK_REQUIRED
25
+ * exists. Measured: ~13,500 characters accepted, ~17,000 rejected. 12,000 is
26
+ * under the observed floor with room to spare.
27
+ *
28
+ * Above this, write the prose to a committed file under `.planner/docs/` and
29
+ * pass `descriptionRef` — see suggestedDescriptionRefPath in payload-fallback.ts.
30
+ */
31
+ export declare const PLANNER_LONG_TEXT_FIELD_MAX_CHARS = 12000;
32
+ /**
33
+ * One sentence for a tool description, so the limit is discoverable at the
34
+ * point of the call instead of after it fails. Every tool taking a long text
35
+ * field appends this to its own description.
36
+ */
37
+ export declare function longTextFieldLimitNotice(field?: string): string;
38
+ /** A tool reply as one result: the human-readable body and the structured
39
+ * payload, with no field present in both. */
40
+ export interface MutationReply {
41
+ text: string;
42
+ structured: Record<string, unknown>;
43
+ }
44
+ /** Who was mutated, in the terms a caller refers to it by. The canonical
45
+ * `ref` is what travels — never the raw text the caller happened to type,
46
+ * which may be a short id, a title or a UUID. */
47
+ export interface MutationIdentity {
48
+ entity: PlannerPayloadEntity;
49
+ ref: string;
50
+ id?: string;
51
+ shortId?: string;
52
+ title?: string;
53
+ status?: string;
54
+ }
55
+ export interface MutationReplyInput {
56
+ identity: MutationIdentity;
57
+ operation: PlannerPayloadOperation;
58
+ /** Fields the caller actually changed, in the order they were received. */
59
+ updatedFields: readonly string[];
60
+ /** The persisted values of those fields, to be echoed back within budget.
61
+ * Keys outside `updatedFields` are ignored: a mutation reply never carries
62
+ * a field the mutation did not touch. */
63
+ changedValues?: Record<string, unknown>;
64
+ /** Diagnostics that are not the entity — description freshness, stale
65
+ * parents, lost checklist ticks, resume-required notices. These are the
66
+ * reason to read a mutation result at all, so they are never trimmed. */
67
+ extras?: Record<string, unknown>;
68
+ /** Extra lines for the human channel, such as a lost-tick warning. */
69
+ notices?: readonly string[];
70
+ /** The command that returns the full entity, for a caller that wants what
71
+ * this reply deliberately leaves out. */
72
+ readBackCommand?: string;
73
+ }
74
+ /**
75
+ * Build the one reply every mutation tool returns.
76
+ *
77
+ * What a caller gets: that the write happened, which fields it touched, the
78
+ * canonical ref and identity of what it touched, the changed values within
79
+ * budget, and every diagnostic. What it does not get: the rest of the
80
+ * entity, which it can read with the command named in `readBack`.
81
+ *
82
+ * `updated` (or `discussed`), `updatedFields` and any `errorCode` keep their
83
+ * exact prior shape — mutation-integrity checking across the whole project
84
+ * reads those three and nothing else.
85
+ */
86
+ export declare function buildMutationReply(input: MutationReplyInput): MutationReply;
87
+ export interface DerivedStatusReadOnlyInput {
88
+ entity: "feature" | "phase";
89
+ ref: string;
90
+ attemptedStatus: string;
91
+ effectiveStatus: string;
92
+ /** Full "retry without the status field" instruction. Each adapter names
93
+ * its own update tool (`planner-feature-update` vs `feature_update`), so
94
+ * this one line stays adapter-supplied rather than templated here —
95
+ * moving it into the core would restate a tool name the core doesn't own. */
96
+ retryAction: string;
97
+ }
98
+ /**
99
+ * A feature/phase `status` field cannot be set directly — it is derived
100
+ * from child phases/tasks. Both adapters carried an identical copy of this
101
+ * refusal for feature_update/phase_update; only the retry line's tool name
102
+ * differs, which is why it is the one caller-supplied piece.
103
+ */
104
+ export declare function derivedStatusReadOnlyReply(input: DerivedStatusReadOnlyInput): MutationReply;
105
+ //# sourceMappingURL=mutation-reply.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mutation-reply.d.ts","sourceRoot":"","sources":["../src/mutation-reply.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAE3F;;;;;;GAMG;AACH,eAAO,MAAM,6BAA6B,OAAQ,CAAC;AAEnD;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,OAAQ,CAAC;AAE9C;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,iCAAiC,QAAS,CAAC;AAExD;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,SAAgB,GAAG,MAAM,CAEtE;AAED;6CAC6C;AAC7C,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAED;;iDAEiD;AACjD,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,oBAAoB,CAAC;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,SAAS,EAAE,uBAAuB,CAAC;IACnC,2EAA2E;IAC3E,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC;;6CAEyC;IACzC,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC;;6EAEyE;IACzE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,sEAAsE;IACtE,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B;6CACyC;IACzC,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAoED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,kBAAkB,GAAG,aAAa,CA6C3E;AAED,MAAM,WAAW,0BAA0B;IACzC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB;;;kFAG8E;IAC9E,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,0BAA0B,GAAG,aAAa,CA4B3F"}