@akagilnc/pi-workflow-roles 0.1.5762 → 0.1.5797

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 (52) hide show
  1. package/dist/acp-host/production-host.js +685 -285
  2. package/dist/external-host-turn-loop.js +3 -0
  3. package/dist/headless-host/production-host.js +658 -258
  4. package/dist/migrate-book-topology.js +70 -29
  5. package/dist/navigator-attendance.js +1 -1
  6. package/dist/packaged-role-registry.js +3 -2
  7. package/dist/pi/role-turn-host.js +6 -1
  8. package/dist/public-cli/instruction-seat-run.js +152 -60
  9. package/dist/public-cli/invocation.js +98 -46
  10. package/dist/public-cli/main.js +482 -222
  11. package/dist/public-cli/option-definitions.js +4 -4
  12. package/dist/public-cli/post-admission.js +19 -28
  13. package/dist/public-cli/run-lifecycle.js +10 -21
  14. package/dist/public-cli/turn-request.js +3 -0
  15. package/dist/public-role-summons.js +11 -8
  16. package/dist/report-ticket-tool.js +3 -3
  17. package/dist/role-run-placement.js +14 -2
  18. package/dist/role-run-relocation.js +2 -2
  19. package/dist/run-dossier.js +5 -4
  20. package/dist/run-terminal-artifacts.js +0 -7
  21. package/dist/session-identity.js +3 -2
  22. package/dist/sitian-appender.js +12 -3
  23. package/dist/submission-ledger.js +24 -0
  24. package/dist/ticket-progress.js +306 -0
  25. package/dist/user-dialogue-stdin.js +23 -17
  26. package/package.json +1 -1
  27. package/src/external-host-turn-loop.ts +7 -1
  28. package/src/host-contracts.ts +1 -1
  29. package/src/navigator-attendance.ts +2 -1
  30. package/src/packaged-role-registry.ts +3 -2
  31. package/src/pi/adapter.ts +57 -45
  32. package/src/pi/role-turn-host.ts +6 -1
  33. package/src/prepared-role-turn.ts +6 -0
  34. package/src/public-cli/instruction-seat-run.ts +166 -68
  35. package/src/public-cli/invocation.ts +120 -46
  36. package/src/public-cli/option-definitions.ts +5 -4
  37. package/src/public-cli/post-admission.ts +19 -30
  38. package/src/public-cli/run-lifecycle.ts +10 -27
  39. package/src/public-cli/turn-request.ts +3 -0
  40. package/src/public-role-summons.ts +27 -16
  41. package/src/report-ticket-tool.ts +7 -3
  42. package/src/role-envelope.ts +5 -0
  43. package/src/role-run-placement.ts +19 -2
  44. package/src/role-run-relocation.ts +2 -2
  45. package/src/role-runtime.ts +19 -2
  46. package/src/run-dossier.ts +5 -3
  47. package/src/run-terminal-artifacts.ts +0 -8
  48. package/src/session-identity.ts +3 -2
  49. package/src/sitian-appender.ts +14 -3
  50. package/src/submission-ledger.ts +27 -0
  51. package/src/ticket-progress.ts +383 -0
  52. package/src/user-dialogue-stdin.ts +21 -14
@@ -8,7 +8,8 @@ import { readFile, realpath, rename, writeFile, } from "node:fs/promises";
8
8
  import { dirname, isAbsolute, join, resolve, sep } from "node:path";
9
9
  import { activationBookDirectory, ensureRealDirectoryTree, homeFromRunDirectory, pathContainedIn, resolveActivationLedgerHome, } from "../activation-ledger-topology.js";
10
10
  import { resolveBookKeyFromGit } from "../activation-ledger-git.js";
11
- import { ensureRoleRunDirectory, ensureRoleRunPlacement, formatRunLeaf, isUnboundRunDirectory, listBookRunDirectories, roleRunPlacement, } from "../role-run-placement.js";
11
+ import { ensureRoleRunDirectory, ensureRoleRunPlacement, isUnboundRunDirectory, listBookRunDirectories, roleRunPlacement, sessionDirectoryOf, sessionFileIn, } from "../role-run-placement.js";
12
+ import { relocateTicketProgressForLeg } from "../ticket-progress.js";
12
13
  import { packagedAdmittedSubject, packagedArgvResult, packagedBareToken, packagedBaseIsRevision, packagedEmitsAuthorityRefs, packagedPublicInstructionSubject, packagedRoleMetadata, packagedStoresSourceRunRaw, packagedSubjectChoices, } from "../packaged-role-registry.js";
13
14
  import { isSafePositiveTicketNumber, parseTicketNumber, readBoardTicketNumber, requireSafePositiveTicketNumber, } from "../run-ticket-number.js";
14
15
  import { rewriteAdmittedRoleRunPage, } from "../role-run-relocation.js";
@@ -243,12 +244,80 @@ export async function recordAdmittedCorrelation(admitted, correlationId) {
243
244
  mutable.correlationId = correlationId;
244
245
  mutable.correlationIds = correlationIds;
245
246
  }
247
+ /**
248
+ * #1199 R2: registered 起居郎 legs that already belong on this ticket.
249
+ * Unbound source → whole-leg rename + publish; already under ticket → publish
250
+ * leftover staging only. No scan of unregistered siblings.
251
+ */
252
+ async function relocateRegisteredChildDiarists(input) {
253
+ const childRunIds = readPageSync(input.parentRunDirectory, "admitted")?.childDiaristRunIds;
254
+ for (const childRunId of Array.isArray(childRunIds) ? childRunIds : []) {
255
+ if (typeof childRunId !== "string")
256
+ continue;
257
+ const childTarget = roleRunPlacement(input.ledgerHome, {
258
+ bookKey: input.bookKey,
259
+ subject: { ticketNumber: input.ticketNumber },
260
+ runId: childRunId,
261
+ role: "diarist",
262
+ });
263
+ const unboundChildDirectory = roleRunPlacement(input.ledgerHome, {
264
+ bookKey: input.bookKey,
265
+ subject: { unbound: true },
266
+ runId: childRunId,
267
+ role: "diarist",
268
+ }).runDirectory;
269
+ if (existsSync(unboundChildDirectory)) {
270
+ input.authority.seal(childTarget);
271
+ await bindTicketNumberOnRunDirectory(unboundChildDirectory, input.ticketNumber);
272
+ await rehomeUnboundTicketProvenance(unboundChildDirectory, input.ticketNumber, input.projectRoot, homeFromRunDirectory(input.parentRunDirectory));
273
+ ensureRoleRunDirectory(input.ledgerHome, dirname(childTarget.runDirectory));
274
+ // #1199: whole-leg rename first; originals travel with the directory.
275
+ await rename(unboundChildDirectory, childTarget.runDirectory);
276
+ relocateTicketProgressForLeg({
277
+ runDirectory: childTarget.runDirectory,
278
+ });
279
+ // Finished child legs will not settle again; refresh derived host.original
280
+ // after the rename commit. A derived render fault must not undo or block
281
+ // the committed placement (#1161 L1) — note and keep the true cause.
282
+ try {
283
+ renderCurrentSync(childTarget.runDirectory);
284
+ }
285
+ catch (error) {
286
+ process.stderr.write(`[invocation] current.json render refused after child relocate; placement kept: ${childTarget.runDirectory}: ${errorText(error)}\n`);
287
+ }
288
+ continue;
289
+ }
290
+ // Prior partial relocate left the child under the ticket with staging still held.
291
+ if (existsSync(childTarget.runDirectory)) {
292
+ relocateTicketProgressForLeg({
293
+ runDirectory: childTarget.runDirectory,
294
+ });
295
+ }
296
+ }
297
+ }
246
298
  /** File a role run under its latest typed ticket identity. */
247
299
  export async function relocateAdmittedRunToTicket(admitted, authority, heldLease) {
248
- if (admitted.ticketNumber === undefined || !isUnboundRunDirectory(admitted.runDirectory))
300
+ if (admitted.ticketNumber === undefined)
301
+ return undefined;
302
+ const ledgerHome = resolveActivationLedgerHome(homeFromRunDirectory(admitted.runDirectory));
303
+ // Already under the ticket: publish leftover progress.jsonl (self + registered children).
304
+ if (!isUnboundRunDirectory(admitted.runDirectory)) {
305
+ relocateTicketProgressForLeg({
306
+ runDirectory: admitted.runDirectory,
307
+ });
308
+ if (admitted.role !== "diarist") {
309
+ await relocateRegisteredChildDiarists({
310
+ parentRunDirectory: admitted.runDirectory,
311
+ bookKey: admitted.bookKey,
312
+ ticketNumber: admitted.ticketNumber,
313
+ projectRoot: admitted.projectRoot,
314
+ ledgerHome,
315
+ authority,
316
+ });
317
+ }
249
318
  return undefined;
319
+ }
250
320
  const oldRunDirectory = admitted.runDirectory;
251
- const ledgerHome = resolveActivationLedgerHome(homeFromRunDirectory(oldRunDirectory));
252
321
  const target = roleRunPlacement(ledgerHome, {
253
322
  bookKey: admitted.bookKey,
254
323
  subject: { ticketNumber: admitted.ticketNumber },
@@ -256,54 +325,41 @@ export async function relocateAdmittedRunToTicket(admitted, authority, heldLease
256
325
  role: admitted.role,
257
326
  });
258
327
  ensureRoleRunDirectory(ledgerHome, dirname(target.runDirectory));
259
- // Host sealing is pure identity projection, but may reject the coordinates.
260
- // Keep that failure before the filesystem commit point.
261
- const principal = authority.seal(target);
328
+ // Pre-flight seal; final seal after the filesystem commit.
329
+ authority.seal(target);
262
330
  if (admitted.role !== "diarist") {
263
- const childRunIds = readPageSync(oldRunDirectory, "admitted")?.childDiaristRunIds;
264
- for (const childRunId of Array.isArray(childRunIds) ? childRunIds : []) {
265
- if (typeof childRunId !== "string")
266
- continue;
267
- const childDirectory = join(dirname(oldRunDirectory), formatRunLeaf(childRunId, "diarist"));
268
- // A child that already filed under a ticket keeps its own assertion.
269
- if (!existsSync(childDirectory))
270
- continue;
271
- const childTarget = roleRunPlacement(ledgerHome, {
272
- bookKey: admitted.bookKey,
273
- subject: { ticketNumber: admitted.ticketNumber },
274
- runId: childRunId,
275
- role: "diarist",
276
- });
277
- authority.seal(childTarget);
278
- await bindTicketNumberOnRunDirectory(childDirectory, admitted.ticketNumber);
279
- await rehomeUnboundTicketProvenance(childDirectory, admitted.ticketNumber, admitted.projectRoot, homeFromRunDirectory(oldRunDirectory));
280
- ensureRoleRunDirectory(ledgerHome, dirname(childTarget.runDirectory));
281
- await rename(childDirectory, childTarget.runDirectory);
282
- // Finished child legs will not settle again; refresh derived host.original
283
- // after the rename commit. A derived render fault must not undo or block
284
- // the committed placement (#1161 L1) — note and keep the true cause.
285
- try {
286
- renderCurrentSync(childTarget.runDirectory);
287
- }
288
- catch (error) {
289
- process.stderr.write(`[invocation] current.json render refused after child relocate; placement kept: ${childTarget.runDirectory}: ${errorText(error)}\n`);
290
- }
291
- }
331
+ await relocateRegisteredChildDiarists({
332
+ parentRunDirectory: oldRunDirectory,
333
+ bookKey: admitted.bookKey,
334
+ ticketNumber: admitted.ticketNumber,
335
+ projectRoot: admitted.projectRoot,
336
+ ledgerHome,
337
+ authority,
338
+ });
292
339
  }
293
340
  // The first ticket assignment moves only an unbound diarist's own diary.
294
341
  if (admitted.role === "diarist") {
295
342
  await rehomeUnboundTicketProvenance(oldRunDirectory, admitted.ticketNumber, admitted.projectRoot, homeFromRunDirectory(oldRunDirectory));
296
343
  }
297
344
  // Rename commits the run placement. Diary assignment above is a Sitian append
298
- // outside the atomic directory move.
299
- // Persisted paths are resolved from typed run identity on read.
345
+ // outside the atomic directory move. Session/receipts/progress travel with the leg.
300
346
  await rename(oldRunDirectory, target.runDirectory);
301
347
  // rename moved the open lock inode with the directory. Transfer cleanup and
302
- // admitted path ownership immediately after the commit — before any derived
303
- // render that may refuse (#1161 L1 / BASE order).
348
+ // live path ownership immediately after the commit — before final seal/render
349
+ // (#1161 L1 / BASE order). Live handles first so mid-turn setSessionFile sees
350
+ // the ticket leaf; final seal uses the post-move existence landing.
304
351
  heldLease?.relocate(target.runDirectory);
352
+ const actualSessionDirectory = sessionDirectoryOf(target.runDirectory);
353
+ const principal = authority.seal({
354
+ sessionDirectory: actualSessionDirectory,
355
+ sessionFile: sessionFileIn(actualSessionDirectory),
356
+ });
305
357
  rewriteAdmittedRoleRunPage(admitted, [{ oldRunDirectory, newRunDirectory: target.runDirectory }]);
306
358
  admitted.principal = principal;
359
+ // After whole-leg rename + live-handle handoff: fill rounds and append ticket current.
360
+ relocateTicketProgressForLeg({
361
+ runDirectory: target.runDirectory,
362
+ });
307
363
  // current.json projects host.original from this run directory. Ownership is
308
364
  // already transferred; a refuse still carries the true cause to the caller
309
365
  // (#1161 L1) without leaving the leg under the unbound path.
@@ -1131,17 +1187,13 @@ export function appendCallerFileFlagPaths(body, attachments, requestManifestPath
1131
1187
  }
1132
1188
  /**
1133
1189
  * One initial prompt transport. The registry `transportPrompt` leaf selects
1134
- * a fixed kickoff, a bound baseline, or skill args. Absent means the caller
1135
- * instruction plus caller file-flag paths (ADR 0087).
1190
+ * a bound baseline or skill args. Absent means the caller instruction plus
1191
+ * caller file-flag paths (ADR 0087). Notary dialogue is owned by
1192
+ * resolveReviewSeatDialogueBody (review fixed dispatch), not an empty transport leaf.
1136
1193
  * Engine / outsourcing material rides startup readingMaterial (#1167), not here.
1137
1194
  */
1138
1195
  export function buildInstructionTransportPrompt(admitted) {
1139
1196
  const kind = admittedTransportPromptKind(admitted);
1140
- if (kind === "fixed-kickoff") {
1141
- // #1166 / ADR 0087: audited-run identity rides startup materials; dialogue
1142
- // prompt is peer body / reask only — never a package-computed directory path.
1143
- return "";
1144
- }
1145
1197
  if (kind === "baseline") {
1146
1198
  if (admitted.baseRevision === undefined) {
1147
1199
  throw new Error("baseline transport prompt is missing the bound revision");