pi-crew 0.11.9 → 0.11.11

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.
@@ -184,25 +184,39 @@ export function validateTaskPacket(packet: TaskPacket): TaskPacketValidationResu
184
184
  }
185
185
 
186
186
  /**
187
- * Structured handoff template for task completion reports.
188
- * Distilled from ECC dmux-workflows pattern — workers use this format
189
- * so verifiers and downstream consumers can parse output predictably.
187
+ * Structured handoff template for task completion reports (U10).
188
+ * Restructured to the 6 PINNED sections of durable's SUMMARIZATION_PROMPT
189
+ * (pi-durable compaction.ts:68-103 — Goal / Constraints & Preferences /
190
+ * Progress (Done·In Progress·Blocked) / Key Decisions / Next Steps /
191
+ * Critical Context), ported per spec U10 so downstream workers and the
192
+ * leader can parse output predictably. The R3-2 `### Provenance` identity
193
+ * footer is retained as the final section — it is an orthogonal pinned
194
+ * contract (worker PI_* self-report, see task-handoff-provenance.test.ts),
195
+ * not one of the 6 content sections.
190
196
  */
191
197
  export const HANDOFF_TEMPLATE = [
192
198
  "## Handoff",
193
199
  "",
194
- "### Summary",
195
- "<!-- 2-3 sentences describing what was done -->",
200
+ "### Goal",
201
+ "<!-- One line: the goal this task served, from the Task Packet objective -->",
196
202
  "",
197
- "### Files Changed",
198
- "<!-- List each file changed with brief description -->",
199
- "<!-- - path/to/file.ts: description -->",
203
+ "### Constraints & Preferences",
204
+ "<!-- Constraints that shaped the work: branch/commit policy, file ownership, style, risk tiers -->",
200
205
  "",
201
- "### Tests / Verification",
202
- "<!-- What tests pass? What was manually verified? -->",
206
+ "### Progress",
207
+ "<!-- Report the state of the work in three groups, each as bullet lists:",
208
+ "Done: completed items, with file paths",
209
+ "In Progress: items underway when this task ended",
210
+ "Blocked: blockers, with the exact reason and owner -->",
203
211
  "",
204
- "### Follow-ups",
205
- "<!-- Any remaining issues or next steps -->",
212
+ "### Key Decisions",
213
+ "<!-- Decisions made and why, with file:line anchors where useful -->",
214
+ "",
215
+ "### Next Steps",
216
+ "<!-- Remaining work, follow-ups, and the recommended next action -->",
217
+ "",
218
+ "### Critical Context",
219
+ "<!-- Verification evidence (commands + outcomes), changed/read files, risks the next worker must know -->",
206
220
  "",
207
221
  "### Provenance",
208
222
  "<!-- Self-report your runtime identity (pre-set in your bash tool env, one line): PI_SESSION_ID, PI_SESSION_FILE, PI_MODEL, PI_PROVIDER, PI_REASONING_LEVEL — e.g. `session=<id> model=<provider>/<model> reasoning=<level>` -->",
@@ -292,6 +306,13 @@ function parseMixedContent(section: string): string[] {
292
306
  * Parse structured handoff data from agent output text.
293
307
  * Looks for the "## Handoff" heading and extracts subsections.
294
308
  * Returns empty arrays for sections not found.
309
+ *
310
+ * U10 note: targets the LEGACY section names (Summary / Files Changed /
311
+ * Tests / Verification / Follow-ups) for backward compatibility with
312
+ * outputs persisted before the 6-section template; the current
313
+ * HANDOFF_TEMPLATE (Goal / Constraints & Preferences / Progress /
314
+ * Key Decisions / Next Steps / Critical Context) has no dedicated parser
315
+ * yet — see spec U10 follow-ups.
295
316
  */
296
317
  export function parseHandoffFromOutput(output: string): ParsedHandoff {
297
318
  if (!output || typeof output !== "string") {
@@ -49,7 +49,7 @@ export function coordinationBridgeInstructions(task: TeamTaskState, opts?: { inc
49
49
  "- Do not resolve cross-worker conflicts silently. Escalate via mailbox/result with: file/symbol, conflicting task if known, proposed owner, and safest next step.",
50
50
  "- If nudged, answer with current status, blocker, or smallest next step.",
51
51
  "- Treat inherited/dependency context as reference-only; do not continue the parent conversation directly.",
52
- "- Completion handoff should include: DONE/FAILED, summary, changed/read files, verification evidence, and remaining risks.",
52
+ "- Completion handoff must use the structured 6-section template (Goal / Constraints & Preferences / Progress / Key Decisions / Next Steps / Critical Context): mark DONE/FAILED and split Done·In Progress·Blocked under Progress, list changed/read files and verification evidence under Critical Context, and surface remaining risks as Next Steps.",
53
53
  ].join("\n");
54
54
  }
55
55
 
@@ -303,9 +303,19 @@ export function promptSkillMode(): "index" | "full" {
303
303
  return getCrewEnv("PI_CREW_PROMPT_SKILLS") === "full" ? "full" : "index";
304
304
  }
305
305
 
306
- /** Estimated tokens (chars/4 — the in-tree heuristic; no tokenizer dep). */
307
- export function estimateTokens(chars: number): number {
308
- return Math.round(chars / 4);
306
+ /** Estimated tokens (chars/4 — the in-tree heuristic; no tokenizer dep).
307
+ * U10 measured-token anchor: when a REAL measurement is available (message_end
308
+ * usage / task result usage persisted on `TeamTaskState.usage`, threaded into
309
+ * the dependency context by `aggregateUsage`), the effective estimate is
310
+ * `max(heuristic, measured)` — a real measurement can only TIGHTEN the
311
+ * estimate, never loosen it, so a budget sized in effective tokens is never
312
+ * exceeded when measured usage is larger than the heuristic (spec U10
313
+ * acceptance). Callers without a measurement keep the plain heuristic.
314
+ * Mirrors `measureHandoffTokens` in src/runtime/task-output-context.ts
315
+ * (duplicated, not imported — see the sync note there). */
316
+ export function estimateTokens(chars: number, measuredTokens?: number): number {
317
+ const heuristic = Math.round(chars / 4);
318
+ return measuredTokens === undefined ? heuristic : Math.max(heuristic, measuredTokens);
309
319
  }
310
320
 
311
321
  export async function renderTaskPrompt(
@@ -380,7 +390,7 @@ export async function renderTaskPrompt(
380
390
  "Task:",
381
391
  sanitizeTaskText(step.task.replaceAll("{goal}", manifest.goal)),
382
392
  "",
383
- "When your task is complete, structure your final output using this handoff template:",
393
+ "When your task is complete, structure your final output using this handoff template (Goal / Constraints & Preferences / Progress / Key Decisions / Next Steps / Critical Context — U10 pinned sections):",
384
394
  HANDOFF_TEMPLATE,
385
395
  ].join("\n");
386
396
 
@@ -491,6 +491,11 @@ export function createRunManifest(params: {
491
491
  `saveManifestAndTasksAtomicSync: manifestWritten=${result.manifestWritten}, tasksWritten=${result.tasksWritten}${cause}`,
492
492
  );
493
493
  }
494
+ // U2 (2026-10-10): kept SYNC — run birth anchor with an EXPLICIT seq:1.
495
+ // createRunManifest is a sync API whose callers may immediately append more
496
+ // events in the same tick (e.g. updateRunStatus(run.running)); a delayed
497
+ // run.created would let those reserve seq 1 from the sidecar first —
498
+ // duplicate seq + inverted audit order. Critical-path same-tick durability.
494
499
  appendEvent(paths.eventsPath, {
495
500
  type: "run.created",
496
501
  runId: paths.runId,
@@ -910,6 +915,10 @@ export function updateRunStatus(
910
915
  // allowTerminalExit for its legitimate cancelled→running transition.
911
916
  const saved = saveRunManifest(updated, { allowTerminalExit: options.allowTerminalExit });
912
917
  if (saved.status !== status) {
918
+ // U2 (2026-10-10): kept SYNC (both updateRunStatus events) — public sync
919
+ // API; same-poll status readers and the 2026-09-10 WI-2.2/M2 remediation
920
+ // (b6eba80f) require same-tick event visibility, and callers may append
921
+ // more events in this same tick that must order around run.<status>.
913
922
  appendEvent(saved.eventsPath, {
914
923
  type: "run.terminal_preserved",
915
924
  runId: saved.runId,
@@ -929,6 +938,8 @@ export function updateRunStatus(
929
938
  /* non-critical */
930
939
  }
931
940
  }
941
+ // U2 (2026-10-10): kept SYNC — see the run.terminal_preserved note above
942
+ // (same-tick visibility for same-poll status readers; b6eba80f).
932
943
  appendEvent(updated.eventsPath, {
933
944
  type: `run.${status}`,
934
945
  runId: updated.runId,