@llblab/pi-actors 0.56.1 → 0.57.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 (44) hide show
  1. package/AGENTS.md +7 -7
  2. package/BACKLOG.md +4 -14
  3. package/CHANGELOG.md +13 -0
  4. package/README.md +7 -2
  5. package/dist/lib/execution-output.js +13 -2
  6. package/dist/lib/observability.js +9 -14
  7. package/dist/lib/registry.js +82 -117
  8. package/dist/lib/run-delivery.d.ts +1 -1
  9. package/dist/lib/run-delivery.js +146 -32
  10. package/dist/lib/run-ui-runtime.js +18 -27
  11. package/dist/lib/runs-process-windows-mi.d.ts +71 -0
  12. package/dist/lib/runs-process-windows-mi.js +146 -3
  13. package/dist/lib/tools-inspect.js +109 -59
  14. package/dist/lib/tools-local.js +16 -8
  15. package/dist/lib/tools-message.js +76 -65
  16. package/dist/lib/tools-response.d.ts +18 -0
  17. package/dist/lib/tools-response.js +88 -21
  18. package/dist/lib/tools-spawn.js +19 -12
  19. package/dist/skills/actors/SKILL.md +1 -1
  20. package/dist/skills/actors/references/diagnostics.md +3 -0
  21. package/dist/skills/actors/references/runs.md +1 -1
  22. package/docs/README.md +1 -0
  23. package/docs/actor-inspector.md +2 -2
  24. package/docs/agent-experience.md +51 -4
  25. package/docs/coordinator-delivery.md +2 -2
  26. package/docs/inactive-foundations-inventory.md +73 -0
  27. package/docs/inspection.md +9 -8
  28. package/docs/output-projection-map.md +19 -17
  29. package/docs/windows-process-observation.md +2 -2
  30. package/lib/execution-output.ts +13 -2
  31. package/lib/observability.ts +9 -11
  32. package/lib/registry.ts +89 -124
  33. package/lib/run-delivery.ts +130 -31
  34. package/lib/run-ui-runtime.ts +18 -34
  35. package/lib/runs-process-windows-mi.ts +167 -3
  36. package/lib/tools-inspect.ts +109 -59
  37. package/lib/tools-local.ts +26 -15
  38. package/lib/tools-message.ts +85 -58
  39. package/lib/tools-response.ts +97 -20
  40. package/lib/tools-spawn.ts +19 -12
  41. package/package.json +1 -1
  42. package/skills/actors/SKILL.md +1 -1
  43. package/skills/actors/references/diagnostics.md +3 -0
  44. package/skills/actors/references/runs.md +1 -1
@@ -278,8 +278,11 @@ function parseInventorySource(value, batch) {
278
278
  function isFrontmatterCompletionLayout(layout) {
279
279
  return layout === "frontmatter_v1" || layout === "frontmatter_v2";
280
280
  }
281
+ function isYamlCompletionLayout(layout) {
282
+ return layout === "completion_yaml_core_v1" || layout === "completion_yaml_files_v1";
283
+ }
281
284
  function isSharedCompletionLayout(layout) {
282
- return layout === "headings_shared_results" || layout === "headings_shared_kinds" || layout === "completion_yaml_core_v1" || isFrontmatterCompletionLayout(layout);
285
+ return layout === "headings_shared_results" || layout === "headings_shared_kinds" || isYamlCompletionLayout(layout) || isFrontmatterCompletionLayout(layout);
283
286
  }
284
287
  function parseBatch(value) {
285
288
  const record = asRecord(value, "Completion batch");
@@ -322,7 +325,7 @@ function parseBatch(value) {
322
325
  throw new Error("Completion shared text budget is invalid");
323
326
  }
324
327
  const numberingDescriptor = Object.getOwnPropertyDescriptor(record, "numbering");
325
- if (numberingDescriptor && (resultLayout === "completion_yaml_core_v1" || !Object.hasOwn(numberingDescriptor, "value") || presentationFormat !== "ax_records" || (resultLayout !== "headings" && resultLayout !== "headings_flat_omissions" && resultLayout !== "headings_outcomes" && !isSharedCompletionLayout(resultLayout)))) {
328
+ if (numberingDescriptor && (isYamlCompletionLayout(resultLayout) || !Object.hasOwn(numberingDescriptor, "value") || presentationFormat !== "ax_records" || (resultLayout !== "headings" && resultLayout !== "headings_flat_omissions" && resultLayout !== "headings_outcomes" && !isSharedCompletionLayout(resultLayout)))) {
326
329
  throw new Error("Completion numbering requires a canonical captured heading layout");
327
330
  }
328
331
  const numbering = numberingDescriptor ? parseCompletionNumbering(numberingDescriptor.value, members.length) : undefined;
@@ -685,7 +688,7 @@ export function requestRunCompletionStream(input) {
685
688
  });
686
689
  }
687
690
  export function admitRunCompletionBatch(input) {
688
- return captureCompletionBatch(input, false, "completion_yaml_core_v1");
691
+ return captureCompletionBatch(input, false, "completion_yaml_files_v1");
689
692
  }
690
693
  /** Kernel-only opt-in; ordinary Pi capture stays fenced until session/lifecycle integration is admitted. */
691
694
  export function captureRunCompletionStreamBatch(input) {
@@ -693,7 +696,7 @@ export function captureRunCompletionStreamBatch(input) {
693
696
  }
694
697
  /** Private ordinary candidate composition; stream capture retains its separately gated codec. */
695
698
  export function captureRunCompletionYamlCandidateBatch(input) {
696
- return captureCompletionBatch(input, false, "completion_yaml_core_v1");
699
+ return captureCompletionBatch(input, false, "completion_yaml_files_v1");
697
700
  }
698
701
  function captureCompletionBatch(input, numbered, layout = "frontmatter_v2") {
699
702
  const now = (input.now ?? new Date()).toISOString();
@@ -710,7 +713,7 @@ function captureCompletionBatch(input, numbered, layout = "frontmatter_v2") {
710
713
  members: input.members,
711
714
  phase: "pending",
712
715
  });
713
- const draft = layout === "completion_yaml_core_v1"
716
+ const draft = isYamlCompletionLayout(layout)
714
717
  ? parseBatch({ ...captured, result_layout: layout }) : { ...captured, result_layout: layout };
715
718
  return mutateJournal(input.tempDir, input.ownerId, (journal) => {
716
719
  let batch = draft;
@@ -741,10 +744,10 @@ function captureCompletionBatch(input, numbered, layout = "frontmatter_v2") {
741
744
  else if (journal.completion_stream) {
742
745
  throw new Error("Completion stream capture requires the numbered kernel path; stream state is retained");
743
746
  }
744
- if (layout !== "completion_yaml_core_v1")
747
+ if (!isYamlCompletionLayout(layout))
745
748
  batch = retainSharedCompletionTexts(batch);
746
749
  if (projectCompletionBatchMessage(batch).membersShown === batch.members.length) {
747
- if (layout === "completion_yaml_core_v1")
750
+ if (isYamlCompletionLayout(layout))
748
751
  batch = retainSharedCompletionTexts(batch);
749
752
  journal.completion_batch = batch;
750
753
  return batch;
@@ -1281,7 +1284,7 @@ function isRoutineCompletionSummary(member) {
1281
1284
  return member.summary === (member.status === "done" ? "Run completed." : `Run ${member.status}.`);
1282
1285
  }
1283
1286
  function completionRecordRow(member, index, byIdentity, flat = false, layout, textBudget) {
1284
- const frontmatter = isFrontmatterCompletionLayout(layout) || layout === "completion_yaml_core_v1";
1287
+ const frontmatter = isFrontmatterCompletionLayout(layout) || isYamlCompletionLayout(layout);
1285
1288
  const simpleKinds = frontmatter || layout === "headings_shared_kinds", shared = isSharedCompletionLayout(layout);
1286
1289
  const outcomes = shared || layout === "headings_outcomes", directOmission = outcomes || layout === "headings_flat_omissions";
1287
1290
  const run = member.run.startsWith("run:") ? member.run.slice(4) : member.run;
@@ -1604,8 +1607,97 @@ function completionYamlReferences(row) {
1604
1607
  })) };
1605
1608
  return technical;
1606
1609
  }
1610
+ /** Split selected paths without normalize/resolve/relative: dot and symlink routes must not be rewritten. */
1611
+ function rootedCompletionPath(path, runRoot) {
1612
+ if (typeof path !== "string" || !path.isWellFormed())
1613
+ return undefined;
1614
+ const windows = /^(?:[A-Za-z]:[\\/]|\\\\[^\\/]+[\\/][^\\/]+[\\/])/u.test(path);
1615
+ const separator = windows ? /[\\/]/u : /\//u;
1616
+ if (!windows && !path.startsWith("/"))
1617
+ return undefined;
1618
+ if (path.split(separator).some(part => part === "." || part === ".."))
1619
+ return undefined;
1620
+ if (runRoot && path.startsWith(runRoot)) {
1621
+ const tail = path.slice(runRoot.length);
1622
+ if (separator.test(runRoot.slice(-1)) ? tail.length > 0 : separator.test(tail[0] ?? "")) {
1623
+ const relative = separator.test(runRoot.slice(-1)) ? tail : tail.slice(1);
1624
+ if (relative && !separator.test(relative[0]))
1625
+ return { root: runRoot, path: relative };
1626
+ }
1627
+ }
1628
+ let split = -1;
1629
+ for (let i = 0; i < path.length; i++)
1630
+ if (separator.test(path[i]))
1631
+ split = i;
1632
+ if (split < 0 || split === path.length - 1)
1633
+ return undefined;
1634
+ const end = split === 0 || (windows && split === 2 && path[1] === ":") ? split + 1 : split;
1635
+ return { root: path.slice(0, end), path: path.slice(split + 1) };
1636
+ }
1637
+ /** Body-free, read-free navigation over already selected references. Roots are presentation bases, not containment proof. */
1638
+ function completionRootedFiles(row, member, locations) {
1639
+ const technical = completionYamlReferences(row), files = {};
1640
+ const groups = [];
1641
+ const runRoot = locations?.state === "available" ? locations.directory : undefined;
1642
+ const group = (root) => {
1643
+ const found = groups.findIndex(item => item.root === root);
1644
+ if (found >= 0)
1645
+ return found;
1646
+ groups.push({ root, entries: [] });
1647
+ return groups.length - 1;
1648
+ };
1649
+ let priority = Infinity;
1650
+ const add = (path, entry, rank = Infinity, base) => {
1651
+ const selected = rootedCompletionPath(path, runRoot);
1652
+ const index = group(selected?.root ?? (base === undefined ? null : completionYamlString(base)));
1653
+ const selectedPath = selected?.path ?? path;
1654
+ groups[index].entries.push({ ...entry, path: selectedPath,
1655
+ ...(!selected && base === undefined ? { path_basis: "as_recorded", base_unavailable: true } : {}) });
1656
+ if (selected && rank < priority) {
1657
+ priority = rank;
1658
+ files.read_first = { group: index, entry: groups[index].entries.length - 1 };
1659
+ }
1660
+ };
1661
+ for (const [role, purpose, rank] of [
1662
+ ["primary", "Full result text", 0], ["diagnostic_metadata", "Recorded error and command metadata", 1],
1663
+ ["artifact_inventory", "Declared artifact inventory; target availability unproven", 2],
1664
+ ]) {
1665
+ const detail = technical[role];
1666
+ if (!detail)
1667
+ continue;
1668
+ const { source: rawSource, ...facts } = detail;
1669
+ const { path, ...binding } = rawSource;
1670
+ add(path, { role, purpose, ...facts, source: binding }, rank);
1671
+ delete technical[role];
1672
+ }
1673
+ const artifacts = technical.artifacts;
1674
+ if (artifacts) {
1675
+ for (const item of artifacts.declarations)
1676
+ add(item.path, { role: "artifact", purpose: "Declared artifact", name: item.name, scope: artifacts.scope, state: "declared" });
1677
+ delete technical.artifacts;
1678
+ }
1679
+ if (locations?.state === "available") {
1680
+ const { directory, files: selectedFiles, ...observation } = locations;
1681
+ files.observation = { ...observation, run: completionYamlString(locations.run), run_instance_id: completionYamlString(locations.run_instance_id),
1682
+ group: group(completionYamlString(directory)) };
1683
+ for (const item of selectedFiles) {
1684
+ const { path, ...facts } = item;
1685
+ const purpose = item.role === "result" ? "Recorded result metadata" : item.role === "execution" ? "Recorded execution and capture locations" : "Recorded Run file";
1686
+ add(typeof path === "string" ? completionYamlString(path) : null, { ...facts, purpose }, item.state === "present" && item.role === "result" ? 3 : item.state === "present" && item.role === "execution" ? 4 : Infinity, directory);
1687
+ }
1688
+ }
1689
+ else if (locations)
1690
+ files.observation = { ...locations, run: completionYamlString(member.run), run_instance_id: completionYamlString(member.run_instance_id) };
1691
+ if (groups.length) {
1692
+ files.groups = groups;
1693
+ }
1694
+ if (Object.keys(technical).length)
1695
+ files.notes = technical;
1696
+ return files;
1697
+ }
1607
1698
  function prepareCompletionYamlProjection(safe, candidates, references, ordered) {
1608
1699
  const packet = { batchId: safe.batch_id, records: [] };
1700
+ const rooted = safe.result_layout === "completion_yaml_files_v1";
1609
1701
  if (!safe.batch_id.isWellFormed())
1610
1702
  return { state: "unsupported" };
1611
1703
  for (const [index, { row, location }] of candidates.entries()) {
@@ -1630,18 +1722,24 @@ function prepareCompletionYamlProjection(safe, candidates, references, ordered)
1630
1722
  else
1631
1723
  metadata[key] = completionYamlString(value);
1632
1724
  }
1633
- const technical = completionYamlReferences(row);
1634
- if (Object.keys(technical).length)
1635
- metadata.references = technical;
1636
- if (references.has(index) && location) {
1637
- const navigation = safe.file_navigation.find(item => safe.members[item.member_index] === member);
1638
- // Navigation is already decoded native data, not the JSON display field.
1639
- const locations = navigation.locations;
1640
- metadata.run_files = { run: completionYamlString(member.run), run_instance_id: completionYamlString(member.run_instance_id),
1641
- locations: locations.state === "available" ? { ...locations, run: completionYamlString(locations.run),
1642
- run_instance_id: completionYamlString(locations.run_instance_id), directory: completionYamlString(locations.directory),
1643
- files: locations.files.map(file => ({ ...file, ...(typeof file.path === "string" ? { path: completionYamlString(file.path) } : {}) })) }
1644
- : { ...locations } };
1725
+ const navigation = references.has(index) && location
1726
+ ? safe.file_navigation.find(item => safe.members[item.member_index] === member).locations : undefined;
1727
+ if (rooted) {
1728
+ const files = completionRootedFiles(row, member, navigation);
1729
+ if (Object.keys(files).length)
1730
+ metadata.files = files;
1731
+ }
1732
+ else {
1733
+ const technical = completionYamlReferences(row);
1734
+ if (Object.keys(technical).length)
1735
+ metadata.references = technical;
1736
+ if (navigation) {
1737
+ metadata.run_files = { run: completionYamlString(member.run), run_instance_id: completionYamlString(member.run_instance_id),
1738
+ locations: navigation.state === "available" ? { ...navigation, run: completionYamlString(navigation.run),
1739
+ run_instance_id: completionYamlString(navigation.run_instance_id), directory: completionYamlString(navigation.directory),
1740
+ files: navigation.files.map(file => ({ ...file, ...(typeof file.path === "string" ? { path: completionYamlString(file.path) } : {}) })) }
1741
+ : { ...navigation } };
1742
+ }
1645
1743
  }
1646
1744
  const parts = [];
1647
1745
  const add = (part) => { if (parts.length)
@@ -1650,13 +1748,22 @@ function prepareCompletionYamlProjection(safe, candidates, references, ordered)
1650
1748
  if (piece.block) {
1651
1749
  if (!piece.text.isWellFormed())
1652
1750
  return { state: "unsupported" };
1653
- add(piece.block === "body" ? { body: piece.text } : { marker: piece.text });
1751
+ if (rooted && piece.block === "marker" && !/^\[[0-9]+ characters omitted\]$/u.test(piece.text)) {
1752
+ metadata.text_warnings ??= [];
1753
+ metadata.text_warnings.push(piece.text);
1754
+ }
1755
+ else
1756
+ add(piece.block === "body" ? { body: piece.text } : { marker: piece.text });
1654
1757
  }
1655
- if (safe.file_navigation !== undefined && !references.has(index))
1656
- add({ marker: "Run-file reference omitted (packet byte limit)." });
1758
+ if (safe.file_navigation !== undefined && !references.has(index)) {
1759
+ if (rooted)
1760
+ metadata.run_files_omission = { reason: "packet_byte_limit", shown: 0, omitted: 1, total: 1 };
1761
+ else
1762
+ add({ marker: "Run-file reference omitted (packet byte limit)." });
1763
+ }
1657
1764
  packet.records.push({ metadata, parts });
1658
1765
  }
1659
- const service = {};
1766
+ const service = rooted ? { header_layout: "rooted_files_v1" } : {};
1660
1767
  const omitted = safe.members.length - candidates.length;
1661
1768
  if (omitted) {
1662
1769
  service.omitted_results = omitted;
@@ -1676,8 +1783,11 @@ function prepareCompletionYamlProjection(safe, candidates, references, ordered)
1676
1783
  if (safe.numbering.kind === "unavailable")
1677
1784
  service.numbering_unavailable = safe.numbering.reason;
1678
1785
  }
1679
- if (safe.inventory_source)
1680
- service.result_inventory = { ...safe.inventory_source, path: completionYamlString(safe.inventory_source.path) };
1786
+ if (safe.inventory_source) {
1787
+ const path = rooted ? rootedCompletionPath(safe.inventory_source.path) : undefined;
1788
+ service.result_inventory = { ...safe.inventory_source,
1789
+ ...(path ? { root: path.root, path: path.path } : { path: completionYamlString(safe.inventory_source.path) }) };
1790
+ }
1681
1791
  if (Object.keys(service).length)
1682
1792
  packet.service = service;
1683
1793
  const chunks = [];
@@ -1737,7 +1847,7 @@ export function projectRunCompletionYamlPrototype(batch) {
1737
1847
  throw error;
1738
1848
  }
1739
1849
  }
1740
- function projectCompletionRecords(safe, assembler = safe.result_layout === "completion_yaml_core_v1" ? "yaml" : "legacy") {
1850
+ function projectCompletionRecords(safe, assembler = isYamlCompletionLayout(safe.result_layout) ? "yaml" : "legacy") {
1741
1851
  const frontmatter = isFrontmatterCompletionLayout(safe.result_layout) || assembler === "yaml";
1742
1852
  const shared = isSharedCompletionLayout(safe.result_layout);
1743
1853
  const maxBytes = shared ? Limits.RUN_COMPLETION_MODEL_MAX_BYTES : Limits.RUN_DELIVERY_MODEL_MAX_BYTES;
@@ -2024,7 +2134,7 @@ export function projectRunCompletionBatchPresentation(batch) {
2024
2134
  if (safe.presentation_format !== "ax_records" && safe.presentation_format !== "ax_records_v3")
2025
2135
  return { content: projectCompletionBatchMessage(safe).message };
2026
2136
  const result = safe.result_layout !== undefined ? projectCompletionRecords(safe) : projectRetainedRecordCompletionBatch(safe);
2027
- if (safe.result_layout === "completion_yaml_core_v1")
2137
+ if (isYamlCompletionLayout(safe.result_layout))
2028
2138
  return { content: result.message, presentation: Object.freeze({
2029
2139
  format: "completion_yaml_core_v1", content_sha256: createHash("sha256").update(result.message).digest("hex"),
2030
2140
  }) };
@@ -2192,10 +2302,14 @@ export function readRunCompletionPresentation(content, value) {
2192
2302
  hint.content_sha256 !== createHash("sha256").update(content).digest("hex"))
2193
2303
  return full;
2194
2304
  const segments = [];
2305
+ const rooted = core.packet.service?.header_layout === "rooted_files_v1";
2306
+ const facts = Object.fromEntries(Object.entries(core.packet.service ?? {}).filter(([key]) => key !== "header_layout"));
2195
2307
  for (const [index, record] of core.packet.records.entries()) {
2196
2308
  if (index)
2197
2309
  segments.push({ kind: "separator", text: "\n" });
2198
- const metadata = Object.fromEntries(Object.entries(record.metadata).filter(([key]) => key !== "references" && key !== "run_files"));
2310
+ const metadata = Object.fromEntries(Object.entries(record.metadata).filter(([key]) => rooted || (key !== "references" && key !== "run_files")));
2311
+ if (rooted && index === 0 && Object.keys(facts).length)
2312
+ metadata.delivery = facts;
2199
2313
  const header = renderYamlMetadata(metadata, completionYamlMaxBytes);
2200
2314
  if (header.state !== "available")
2201
2315
  return full;
@@ -2203,13 +2317,13 @@ export function readRunCompletionPresentation(content, value) {
2203
2317
  for (const part of record.parts)
2204
2318
  segments.push("body" in part ? { kind: "body", text: part.body } : { kind: "marker", text: part.marker });
2205
2319
  }
2206
- if (core.packet.service) {
2207
- const service = renderYamlMetadata(core.packet.service, completionYamlMaxBytes);
2320
+ if (core.packet.service && (!rooted || !core.packet.records.length)) {
2321
+ const service = renderYamlMetadata(rooted ? facts : core.packet.service, completionYamlMaxBytes);
2208
2322
  if (service.state !== "available")
2209
2323
  return full;
2210
2324
  if (segments.length)
2211
2325
  segments.push({ kind: "separator", text: "\n" });
2212
- segments.push({ kind: "service", text: service.text.replace(/\n$/u, "") });
2326
+ segments.push({ kind: rooted ? "header" : "service", text: service.text.replace(/\n$/u, "") });
2213
2327
  }
2214
2328
  return { text: segments.map(segment => segment.text).join("\n"), compact: true, records: true, yaml: true,
2215
2329
  segments: Object.freeze(segments.map(segment => Object.freeze(segment))) };
@@ -12,26 +12,21 @@ import * as Pi from "./pi.js";
12
12
  import * as RunDelivery from "./run-delivery.js";
13
13
  import * as RunDeliveryLineage from "./run-delivery-lineage.js";
14
14
  import * as RunIndex from "./runs-index.js";
15
- import { formatLiteralBlock, formatMarkdownField } from "./tools-response.js";
15
+ import { formatYamlNotice } from "./tools-response.js";
16
16
  function formatSteerDiagnosticMessage(eventId, stage, message) {
17
- const fields = [formatMarkdownField("event", eventId), formatMarkdownField("attention", "steer"),
18
- formatMarkdownField("stage", stage), formatMarkdownField("result", stage === "admission" ? "remains retryable" : "request failed")];
19
- if (stage === "delivery")
20
- fields.push(formatMarkdownField("delivery", "unconfirmed"), formatMarkdownField("presentation", "unconfirmed"));
21
17
  let end = Math.min(message.length, 240);
22
18
  const last = message.charCodeAt(end - 1), next = message.charCodeAt(end);
23
19
  if (last >= 0xd800 && last <= 0xdbff && next >= 0xdc00 && next <= 0xdfff)
24
20
  end -= 1;
25
21
  const preview = message.slice(0, end), clipped = end < message.length;
26
- if (Buffer.from(preview).toString("utf8") !== preview) {
27
- fields.push(formatMarkdownField("diagnostic", "unavailable"), formatMarkdownField("diagnostic_reason", "malformed legacy preview"), formatMarkdownField("diagnostic_omission", "[omitted: unknown]"));
28
- }
29
- else {
30
- fields.push(formatMarkdownField("diagnostic", preview + (clipped ? "…" : "")));
31
- if (clipped)
32
- fields.push(formatMarkdownField("diagnostic_omission", "[omitted: unknown]"));
33
- }
34
- return fields.join("\n");
22
+ // The 240-pair-aligned preview and its explicit unknown-loss marker are unchanged; only metadata is YAML.
23
+ const diagnostic = Buffer.from(preview).toString("utf8") !== preview
24
+ ? { diagnostic: "unavailable", diagnostic_reason: "malformed legacy preview", diagnostic_omission: "[omitted: unknown]" }
25
+ : { diagnostic: preview + (clipped ? "…" : ""), ...(clipped ? { diagnostic_omission: "[omitted: unknown]" } : {}) };
26
+ return formatYamlNotice({ event: eventId, attention: "steer", stage,
27
+ result: stage === "admission" ? "remains retryable" : "request failed",
28
+ ...(stage === "delivery" ? { delivery: "unconfirmed", presentation: "unconfirmed" } : {}),
29
+ ...diagnostic });
35
30
  }
36
31
  /** Transcript-only view of the exact delivered content; never re-read a Run or infer body labels. */
37
32
  export function registerRunCompletionRenderer(pi) {
@@ -162,8 +157,7 @@ export function createRunUiRuntime(deps) {
162
157
  }
163
158
  const message = error instanceof Error ? error.message : String(error);
164
159
  try {
165
- expectedContext.ui.notify([formatMarkdownField("callback", label), formatMarkdownField("result", "failed"),
166
- formatMarkdownField("diagnostic", message)].join("\n"), "error");
160
+ expectedContext.ui.notify(formatYamlNotice({ callback: label, result: "failed", diagnostic: message }), "error");
167
161
  }
168
162
  catch {
169
163
  /* stale context or unavailable UI */
@@ -327,9 +321,8 @@ export function createRunUiRuntime(deps) {
327
321
  const key = `${batch.batch_id}:${evidence.status}:${evidence.reason ?? ""}`;
328
322
  if (!completionDiagnostics.has(key)) {
329
323
  completionDiagnostics.add(key);
330
- ctx.ui.notify("\n" + [formatMarkdownField("batch", batch.batch_id), formatMarkdownField("stage", "completion recovery"),
331
- formatMarkdownField("evidence", evidence.status), formatMarkdownField("phase", "pending"),
332
- formatMarkdownField("reason", evidence.reason ?? "conflicting session evidence")].join("\n"), "warning");
324
+ ctx.ui.notify("\n" + formatYamlNotice({ batch: batch.batch_id, stage: "completion recovery",
325
+ evidence: evidence.status, phase: "pending", reason: evidence.reason ?? "conflicting session evidence" }), "warning");
333
326
  }
334
327
  return true;
335
328
  }
@@ -413,9 +406,8 @@ export function createRunUiRuntime(deps) {
413
406
  const key = `${steer.steer_id}:${evidence.status}:${evidence.reason ?? ""}`;
414
407
  if (!steerDiagnostics.has(key)) {
415
408
  steerDiagnostics.add(key);
416
- ctx.ui.notify([formatMarkdownField("event", steer.event_id), formatMarkdownField("attention", "steer"),
417
- formatMarkdownField("stage", "recovery"), formatMarkdownField("evidence", evidence.status),
418
- formatMarkdownField("phase", "queued"), formatMarkdownField("reason", evidence.reason ?? "conflicting session evidence")].join("\n"), "warning");
409
+ ctx.ui.notify(formatYamlNotice({ event: steer.event_id, attention: "steer", stage: "recovery",
410
+ evidence: evidence.status, phase: "queued", reason: evidence.reason ?? "conflicting session evidence" }), "warning");
419
411
  }
420
412
  continue;
421
413
  }
@@ -681,11 +673,10 @@ export function createRunUiRuntime(deps) {
681
673
  if (teardown.failed === 0 || !ctx)
682
674
  return;
683
675
  try {
684
- ctx.ui.notify([formatMarkdownField("stage", "shutdown teardown"), formatMarkdownField("killed", String(teardown.killed)),
685
- formatMarkdownField("failed", String(teardown.failed)), formatMarkdownField("skipped", String(teardown.skipped)),
686
- formatMarkdownField("discovery_failed", String(teardown.discoveryFailed)),
687
- formatMarkdownField("summary", teardown.summaryPath == null ? "unavailable" : formatLiteralBlock(teardown.summaryPath)),
688
- formatMarkdownField("basis", "teardown report; not scope closure")].join("\n"), "warning");
676
+ ctx.ui.notify(formatYamlNotice({ stage: "shutdown teardown", killed: teardown.killed,
677
+ failed: teardown.failed, skipped: teardown.skipped, discovery_failed: teardown.discoveryFailed,
678
+ summary: teardown.summaryPath ?? "unavailable",
679
+ basis: "teardown report; not scope closure" }), "warning");
689
680
  }
690
681
  catch {
691
682
  /* stale shutdown context */
@@ -43,4 +43,75 @@ export declare function decodeProvenanceBinding(value: unknown): {
43
43
  readonly reason: 'invalid_binding';
44
44
  };
45
45
  export declare function decodeResponse(bytes: Uint8Array, profile: unknown, pids: unknown): DecodeOutcome;
46
+ /**
47
+ * Complete-helper manifest claim. Bounded reading, exact-key schema and closed lexemes only; a valid
48
+ * manifest is integrity/provenance input, never executable authenticity, an approved asset or activation.
49
+ */
50
+ type HelperManifest = {
51
+ readonly helper_version: string;
52
+ readonly architecture: 'windows-x64';
53
+ readonly protocol: 'native-mi-v1';
54
+ readonly profiles: readonly ['scalar', 'shared'];
55
+ readonly native_source_sha256: string;
56
+ readonly executable_bytes: number;
57
+ readonly executable_sha256: string;
58
+ readonly toolchain: {
59
+ readonly compiler: string;
60
+ readonly sdk: string;
61
+ readonly build_arguments: readonly string[];
62
+ };
63
+ readonly dependencies: readonly string[];
64
+ readonly originating_source_commit: string;
65
+ readonly originating_build_job: string;
66
+ };
67
+ type ManifestUnusable = {
68
+ readonly kind: 'unusable';
69
+ readonly reason: 'oversize_manifest' | 'invalid_manifest' | 'unsupported_manifest';
70
+ };
71
+ /** Bounded complete-manifest reader: one strict UTF-8 JSON document with an exact reviewed shape. */
72
+ export declare function readHelperManifest(bytes: Uint8Array): {
73
+ readonly kind: 'manifest_unadmitted';
74
+ readonly manifest: HelperManifest;
75
+ } | ManifestUnusable;
76
+ type HelperAssetLocation = {
77
+ readonly kind: 'located';
78
+ readonly helper_version: string;
79
+ readonly manifest_url: URL;
80
+ readonly executable_url: URL;
81
+ };
82
+ /**
83
+ * Fixed versioned package-relative lookup. Never searches cwd, PATH or caller locations: the only base is
84
+ * the sibling `native/` directory of this module's own `lib/` (source) or `dist/lib/` (compiled) home.
85
+ */
86
+ export declare function resolveHelperAsset(moduleUrl: unknown, runtime: unknown, helperVersion: unknown): HelperAssetLocation | {
87
+ readonly kind: 'unusable';
88
+ readonly reason: 'unsupported_location' | 'unsupported_target' | 'unsupported_version';
89
+ };
90
+ /** Injected bounded reader: exact bytes for one fixed URL or nothing. Never a path, cwd or PATH lookup. */
91
+ export type HelperAssetReader = (url: URL, maximumBytes: number) => Uint8Array | undefined;
92
+ type HelperAssetOutcome = {
93
+ readonly kind: 'asset_verified_unadmitted';
94
+ readonly manifest: HelperManifest;
95
+ readonly executable_sha256: string;
96
+ readonly executable_bytes: number;
97
+ } | {
98
+ readonly kind: 'unusable';
99
+ readonly reason: 'missing_manifest' | 'oversize_manifest' | 'invalid_manifest' | 'unsupported_manifest' | 'version_mismatch' | 'missing_asset' | 'oversize_asset' | 'size_mismatch' | 'digest_mismatch';
100
+ };
101
+ /** Trusted exact-byte selection: bounded manifest read, exact declared size, then exact SHA-256 match. */
102
+ export declare function loadHelperAsset(location: HelperAssetLocation, read: HelperAssetReader): HelperAssetOutcome;
103
+ type HelperInvocation = {
104
+ readonly kind: 'invocation_unadmitted';
105
+ readonly command: string;
106
+ readonly args: readonly string[];
107
+ readonly options: {
108
+ readonly shell: false;
109
+ readonly windowsHide: true;
110
+ };
111
+ } | {
112
+ readonly kind: 'unusable';
113
+ readonly reason: 'unsupported_executable' | 'invalid_query';
114
+ };
115
+ /** Shell-free invocation spec only: no spawn, retry, fallback or execution-policy bypass. */
116
+ export declare function helperInvocation(executablePath: unknown, profile: unknown, pids: unknown): HelperInvocation;
46
117
  export {};
@@ -1,6 +1,13 @@
1
- // Owns: Bounded raw MI wire decoding, query inputs and unadmitted provenance fragments, subordinate to process acquisition.
2
- // Excludes: Identity construction/digest/comparison, status/liveness/lifecycle/publication/admission,
3
- // fallback, native invocation and asset loading. Decoded data never admits a representation profile.
1
+ // Owns: Bounded raw MI wire decoding, query inputs, unadmitted provenance fragments, and unrouted
2
+ // helper manifest/asset verification plus a shell-free invocation spec, subordinate to process acquisition.
3
+ // Excludes: Identity construction/digest/comparison, status/liveness/lifecycle/publication/admission, fallback,
4
+ // process spawning and package inventory. No production reader imports this owner; decoded data, verified
5
+ // asset bytes and the invocation spec never admit a representation profile, architecture or activation.
6
+ import { createHash } from 'node:crypto';
7
+ const MANIFEST_MAX_BYTES = 32 * 1024;
8
+ const EXECUTABLE_MAX_BYTES = 8 * 1024 * 1024;
9
+ const HELPER_VERSION = /^(?:0|[1-9][0-9]{0,5})\.(?:0|[1-9][0-9]{0,5})\.(?:0|[1-9][0-9]{0,5})$/u;
10
+ const MODULE_FILE = /\/lib\/runs-process-windows-mi\.(?:ts|js)$/u;
4
11
  export function queryArguments(profile, pids) {
5
12
  if ((profile !== 'scalar' && profile !== 'shared') || !Array.isArray(pids) ||
6
13
  pids.length < 1 || pids.length > 64 || (profile === 'scalar' && pids.length !== 1))
@@ -112,3 +119,139 @@ export function decodeResponse(bytes, profile, pids) {
112
119
  return { kind: 'unusable', reason: 'unsupported_optional_fields' };
113
120
  return { kind: 'decoded_unadmitted', rows };
114
121
  }
122
+ function boundedText(bytes, maximumBytes) {
123
+ if (!(bytes instanceof Uint8Array) || bytes.byteLength > maximumBytes)
124
+ return undefined;
125
+ if (bytes[0] === 0xef && bytes[1] === 0xbb && bytes[2] === 0xbf)
126
+ return undefined;
127
+ try {
128
+ return new TextDecoder('utf-8', { fatal: true }).decode(bytes);
129
+ }
130
+ catch {
131
+ return undefined;
132
+ }
133
+ }
134
+ function boundedLexemes(value, maximum) {
135
+ if (!Array.isArray(value) || value.length > maximum)
136
+ return undefined;
137
+ const selected = [];
138
+ for (const item of value) {
139
+ if (typeof item !== 'string' || item.length === 0 || item.length > 128 || !/^[\x20-\x7e]+$/.test(item) || selected.includes(item))
140
+ return undefined;
141
+ selected.push(item);
142
+ }
143
+ return selected;
144
+ }
145
+ /** Bounded complete-manifest reader: one strict UTF-8 JSON document with an exact reviewed shape. */
146
+ export function readHelperManifest(bytes) {
147
+ const invalid = { kind: 'unusable', reason: 'invalid_manifest' };
148
+ if (!(bytes instanceof Uint8Array) || bytes.byteLength > MANIFEST_MAX_BYTES)
149
+ return { kind: 'unusable', reason: 'oversize_manifest' };
150
+ const text = boundedText(bytes, MANIFEST_MAX_BYTES);
151
+ if (text === undefined)
152
+ return invalid;
153
+ let value;
154
+ try {
155
+ value = JSON.parse(text);
156
+ }
157
+ catch {
158
+ return invalid;
159
+ }
160
+ if (!exactKeys(value, ['helper_version', 'architecture', 'protocol', 'profiles', 'native_source_sha256',
161
+ 'executable_bytes', 'executable_sha256', 'toolchain', 'dependencies', 'originating_source_commit', 'originating_build_job']))
162
+ return invalid;
163
+ const { helper_version, architecture, protocol, profiles, native_source_sha256, executable_bytes, executable_sha256, toolchain, dependencies, originating_source_commit, originating_build_job } = value;
164
+ if (typeof helper_version !== 'string' || !HELPER_VERSION.test(helper_version) ||
165
+ architecture !== 'windows-x64' || protocol !== 'native-mi-v1' ||
166
+ !Array.isArray(profiles) || profiles.length !== 2 || profiles[0] !== 'scalar' || profiles[1] !== 'shared')
167
+ return { kind: 'unusable', reason: 'unsupported_manifest' };
168
+ if (typeof native_source_sha256 !== 'string' || !/^[0-9a-f]{64}$/.test(native_source_sha256) ||
169
+ typeof executable_sha256 !== 'string' || !/^[0-9a-f]{64}$/.test(executable_sha256) ||
170
+ typeof originating_source_commit !== 'string' || !/^[0-9a-f]{40}$/.test(originating_source_commit) ||
171
+ typeof originating_build_job !== 'string' || !/^[1-9][0-9]*$/.test(originating_build_job) ||
172
+ typeof executable_bytes !== 'number' || !Number.isSafeInteger(executable_bytes) || executable_bytes <= 0)
173
+ return invalid;
174
+ if (executable_bytes > EXECUTABLE_MAX_BYTES)
175
+ return { kind: 'unusable', reason: 'unsupported_manifest' };
176
+ if (!exactKeys(toolchain, ['compiler', 'sdk', 'build_arguments']))
177
+ return invalid;
178
+ const compiler = boundedLexemes([toolchain.compiler], 1)?.[0];
179
+ const sdk = boundedLexemes([toolchain.sdk], 1)?.[0];
180
+ const buildArguments = boundedLexemes(toolchain.build_arguments, 32);
181
+ const dependencyNames = boundedLexemes(dependencies, 32);
182
+ if (compiler === undefined || sdk === undefined || buildArguments === undefined || dependencyNames === undefined)
183
+ return invalid;
184
+ // Fresh primitive claims only; the caller still owns target/version/source-digest policy.
185
+ return {
186
+ kind: 'manifest_unadmitted',
187
+ manifest: {
188
+ helper_version, architecture: 'windows-x64', protocol: 'native-mi-v1', profiles: ['scalar', 'shared'],
189
+ native_source_sha256, executable_bytes, executable_sha256,
190
+ toolchain: { compiler, sdk, build_arguments: buildArguments }, dependencies: dependencyNames,
191
+ originating_source_commit, originating_build_job,
192
+ },
193
+ };
194
+ }
195
+ /**
196
+ * Fixed versioned package-relative lookup. Never searches cwd, PATH or caller locations: the only base is
197
+ * the sibling `native/` directory of this module's own `lib/` (source) or `dist/lib/` (compiled) home.
198
+ */
199
+ export function resolveHelperAsset(moduleUrl, runtime, helperVersion) {
200
+ let url;
201
+ try {
202
+ url = new URL(String(moduleUrl));
203
+ }
204
+ catch {
205
+ return { kind: 'unusable', reason: 'unsupported_location' };
206
+ }
207
+ if (url.protocol !== 'file:' || !MODULE_FILE.test(url.pathname))
208
+ return { kind: 'unusable', reason: 'unsupported_location' };
209
+ const target = runtime;
210
+ if (target?.platform !== 'win32' || target?.arch !== 'x64')
211
+ return { kind: 'unusable', reason: 'unsupported_target' };
212
+ if (typeof helperVersion !== 'string' || !HELPER_VERSION.test(helperVersion))
213
+ return { kind: 'unusable', reason: 'unsupported_version' };
214
+ const directory = `../native/windows-mi/win32-x64/${helperVersion}/`;
215
+ return {
216
+ kind: 'located', helper_version: helperVersion,
217
+ manifest_url: new URL(`${directory}manifest.json`, url),
218
+ executable_url: new URL(`${directory}helper.exe`, url),
219
+ };
220
+ }
221
+ /** Trusted exact-byte selection: bounded manifest read, exact declared size, then exact SHA-256 match. */
222
+ export function loadHelperAsset(location, read) {
223
+ const manifestBytes = read(location.manifest_url, MANIFEST_MAX_BYTES + 1);
224
+ if (manifestBytes === undefined)
225
+ return { kind: 'unusable', reason: 'missing_manifest' };
226
+ if (manifestBytes.byteLength > MANIFEST_MAX_BYTES)
227
+ return { kind: 'unusable', reason: 'oversize_manifest' };
228
+ const reading = readHelperManifest(manifestBytes);
229
+ if (reading.kind === 'unusable')
230
+ return { kind: 'unusable', reason: reading.reason };
231
+ const { manifest } = reading;
232
+ if (manifest.helper_version !== location.helper_version)
233
+ return { kind: 'unusable', reason: 'version_mismatch' };
234
+ // One extra byte detects growth; a shorter read can never satisfy the declared size.
235
+ const executableBytes = read(location.executable_url, manifest.executable_bytes + 1);
236
+ if (executableBytes === undefined)
237
+ return { kind: 'unusable', reason: 'missing_asset' };
238
+ if (executableBytes.byteLength > manifest.executable_bytes)
239
+ return { kind: 'unusable', reason: 'oversize_asset' };
240
+ if (executableBytes.byteLength !== manifest.executable_bytes)
241
+ return { kind: 'unusable', reason: 'size_mismatch' };
242
+ const digest = createHash('sha256').update(executableBytes).digest('hex');
243
+ if (digest !== manifest.executable_sha256)
244
+ return { kind: 'unusable', reason: 'digest_mismatch' };
245
+ return { kind: 'asset_verified_unadmitted', manifest, executable_sha256: digest, executable_bytes: executableBytes.byteLength };
246
+ }
247
+ /** Shell-free invocation spec only: no spawn, retry, fallback or execution-policy bypass. */
248
+ export function helperInvocation(executablePath, profile, pids) {
249
+ if (typeof executablePath !== 'string' || executablePath.length === 0 || executablePath.length > 4096 ||
250
+ !/^[A-Za-z]:[\\/][^\x00\r\n"]*\.exe$/.test(executablePath))
251
+ return { kind: 'unusable', reason: 'unsupported_executable' };
252
+ const query = queryArguments(profile, pids);
253
+ if (!query)
254
+ return { kind: 'unusable', reason: 'invalid_query' };
255
+ return { kind: 'invocation_unadmitted', command: executablePath, args: query,
256
+ options: { shell: false, windowsHide: true } };
257
+ }