@llblab/pi-actors 0.33.0 → 0.34.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 (155) hide show
  1. package/AGENTS.md +22 -11
  2. package/BACKLOG.md +3 -34
  3. package/CHANGELOG.md +14 -0
  4. package/dist/index.js +10 -10
  5. package/dist/lib/async-runs.d.ts +23 -75
  6. package/dist/lib/async-runs.js +49 -801
  7. package/dist/lib/command-templates.d.ts +3 -3
  8. package/dist/lib/command-templates.js +3 -3
  9. package/dist/lib/config.d.ts +2 -2
  10. package/dist/lib/config.js +5 -5
  11. package/dist/lib/{output.d.ts → execution-output.d.ts} +3 -3
  12. package/dist/lib/{output.js → execution-output.js} +3 -3
  13. package/dist/lib/execution.js +1 -1
  14. package/dist/lib/{actor-inspector-tui.d.ts → inspector.d.ts} +3 -2
  15. package/dist/lib/{actor-inspector-tui.js → inspector.js} +3 -2
  16. package/dist/lib/mailbox-loop.d.ts +3 -3
  17. package/dist/lib/mailbox-loop.js +3 -3
  18. package/dist/lib/{actor-messages.d.ts → messages.d.ts} +3 -3
  19. package/dist/lib/{actor-messages.js → messages.js} +3 -3
  20. package/dist/lib/{actor-recipe-context.d.ts → recipes-context.d.ts} +3 -2
  21. package/dist/lib/{actor-recipe-context.js → recipes-context.js} +2 -1
  22. package/dist/lib/{recipe-discovery.d.ts → recipes-discovery.d.ts} +8 -8
  23. package/dist/lib/{recipe-discovery.js → recipes-discovery.js} +6 -6
  24. package/dist/lib/registry.d.ts +1 -1
  25. package/dist/lib/registry.js +22 -22
  26. package/dist/lib/{actor-rooms.d.ts → rooms.d.ts} +4 -4
  27. package/dist/lib/{actor-rooms.js → rooms.js} +3 -3
  28. package/dist/lib/runs-artifacts.d.ts +21 -0
  29. package/dist/lib/runs-artifacts.js +68 -0
  30. package/dist/lib/runs-control.d.ts +13 -0
  31. package/dist/lib/runs-control.js +59 -0
  32. package/dist/lib/runs-identity.d.ts +5 -0
  33. package/dist/lib/runs-identity.js +11 -0
  34. package/dist/lib/runs-index.d.ts +18 -0
  35. package/dist/lib/runs-index.js +119 -0
  36. package/dist/lib/runs-mailbox.d.ts +25 -0
  37. package/dist/lib/runs-mailbox.js +146 -0
  38. package/dist/lib/runs-messages.d.ts +15 -0
  39. package/dist/lib/runs-messages.js +179 -0
  40. package/dist/lib/runs-outbox.d.ts +41 -0
  41. package/dist/lib/runs-outbox.js +87 -0
  42. package/dist/lib/runs-process.d.ts +7 -0
  43. package/dist/lib/runs-process.js +36 -0
  44. package/dist/lib/runs-retention.d.ts +8 -0
  45. package/dist/lib/runs-retention.js +56 -0
  46. package/dist/lib/runs-start.d.ts +9 -0
  47. package/dist/lib/runs-start.js +67 -0
  48. package/dist/lib/runs-status.d.ts +8 -0
  49. package/dist/lib/runs-status.js +60 -0
  50. package/dist/lib/runtime.d.ts +2 -2
  51. package/dist/lib/runtime.js +5 -5
  52. package/dist/lib/schema.d.ts +9 -0
  53. package/dist/lib/schema.js +40 -0
  54. package/dist/lib/tools-access.d.ts +19 -0
  55. package/dist/lib/tools-access.js +44 -0
  56. package/dist/lib/tools-inspect.d.ts +11 -0
  57. package/dist/lib/tools-inspect.js +534 -0
  58. package/dist/lib/tools-local.d.ts +14 -0
  59. package/dist/lib/tools-local.js +156 -0
  60. package/dist/lib/tools-mailbox.d.ts +8 -0
  61. package/dist/lib/tools-mailbox.js +48 -0
  62. package/dist/lib/tools-message.d.ts +9 -0
  63. package/dist/lib/tools-message.js +428 -0
  64. package/dist/lib/tools-register.d.ts +18 -0
  65. package/dist/lib/tools-register.js +40 -0
  66. package/dist/lib/tools-response.d.ts +21 -0
  67. package/dist/lib/tools-response.js +219 -0
  68. package/dist/lib/tools-spawn.d.ts +12 -0
  69. package/dist/lib/tools-spawn.js +159 -0
  70. package/dist/lib/tools.d.ts +8 -39
  71. package/dist/lib/tools.js +11 -1490
  72. package/dist/recipes/utility-coordinator-lock-snapshot.json +1 -1
  73. package/dist/scripts/actor-worker.mjs +190 -7
  74. package/dist/scripts/async-runner.mjs +171 -8
  75. package/dist/scripts/build-dist.mjs +1 -1
  76. package/dist/scripts/conformance.mjs +3 -3
  77. package/dist/scripts/coordinator.mjs +733 -11
  78. package/dist/scripts/locker.mjs +345 -16
  79. package/dist/scripts/recipe-utils.mjs +478 -14
  80. package/dist/scripts/validate-recipe.mjs +110 -10
  81. package/dist/skills/actors/SKILL.md +1 -1
  82. package/dist/skills/swarm/SKILL.md +1 -1
  83. package/docs/recipe-library.md +1 -1
  84. package/docs/template-recipes.md +1 -1
  85. package/index.ts +11 -18
  86. package/lib/async-runs.ts +124 -1016
  87. package/lib/command-templates.ts +3 -3
  88. package/lib/config.ts +7 -7
  89. package/lib/{output.ts → execution-output.ts} +3 -3
  90. package/lib/execution.ts +5 -1
  91. package/lib/{actor-inspector-tui.ts → inspector.ts} +4 -3
  92. package/lib/mailbox-loop.ts +3 -3
  93. package/lib/{actor-messages.ts → messages.ts} +3 -3
  94. package/lib/{actor-recipe-context.ts → recipes-context.ts} +3 -2
  95. package/lib/{recipe-discovery.ts → recipes-discovery.ts} +19 -19
  96. package/lib/{recipe-usage.ts → recipes-usage.ts} +2 -2
  97. package/lib/registry.ts +37 -24
  98. package/lib/{actor-rooms.ts → rooms.ts} +4 -4
  99. package/lib/runs-artifacts.ts +96 -0
  100. package/lib/runs-control.ts +85 -0
  101. package/lib/runs-identity.ts +14 -0
  102. package/lib/runs-index.ts +156 -0
  103. package/lib/runs-mailbox.ts +208 -0
  104. package/lib/runs-messages.ts +252 -0
  105. package/lib/runs-outbox.ts +144 -0
  106. package/lib/runs-process.ts +51 -0
  107. package/lib/runs-retention.ts +77 -0
  108. package/lib/runs-start.ts +98 -0
  109. package/lib/runs-status.ts +78 -0
  110. package/lib/runtime.ts +6 -6
  111. package/lib/schema.ts +55 -0
  112. package/lib/tools-access.ts +68 -0
  113. package/lib/tools-inspect.ts +735 -0
  114. package/lib/tools-local.ts +234 -0
  115. package/lib/tools-mailbox.ts +56 -0
  116. package/lib/tools-message.ts +569 -0
  117. package/lib/tools-register.ts +64 -0
  118. package/lib/tools-response.ts +267 -0
  119. package/lib/tools-spawn.ts +240 -0
  120. package/lib/tools.ts +20 -2040
  121. package/package.json +1 -1
  122. package/recipes/utility-coordinator-lock-snapshot.json +1 -1
  123. package/scripts/actor-worker.mjs +190 -7
  124. package/scripts/async-runner.mjs +171 -8
  125. package/scripts/build-dist.mjs +1 -1
  126. package/scripts/conformance.mjs +3 -3
  127. package/scripts/coordinator.mjs +733 -11
  128. package/scripts/locker.mjs +345 -16
  129. package/scripts/recipe-utils.mjs +478 -14
  130. package/scripts/validate-recipe.mjs +110 -10
  131. package/skills/actors/SKILL.md +1 -1
  132. package/skills/swarm/SKILL.md +1 -1
  133. package/dist/lib/actor-worker.d.ts +0 -16
  134. package/dist/lib/actor-worker.js +0 -134
  135. package/dist/lib/async-runner.d.ts +0 -5
  136. package/dist/lib/async-runner.js +0 -134
  137. package/dist/lib/coordinator.d.ts +0 -5
  138. package/dist/lib/coordinator.js +0 -660
  139. package/dist/lib/locker.d.ts +0 -5
  140. package/dist/lib/locker.js +0 -310
  141. package/dist/lib/recipe-utils.d.ts +0 -5
  142. package/dist/lib/recipe-utils.js +0 -385
  143. package/dist/lib/validate-recipe.d.ts +0 -6
  144. package/dist/lib/validate-recipe.js +0 -104
  145. package/lib/actor-worker.ts +0 -174
  146. package/lib/async-runner.ts +0 -173
  147. package/lib/coordinator.ts +0 -742
  148. package/lib/locker.ts +0 -340
  149. package/lib/recipe-utils.ts +0 -486
  150. package/lib/validate-recipe.ts +0 -110
  151. /package/dist/lib/{recipe-references.d.ts → recipes-references.d.ts} +0 -0
  152. /package/dist/lib/{recipe-references.js → recipes-references.js} +0 -0
  153. /package/dist/lib/{recipe-usage.d.ts → recipes-usage.d.ts} +0 -0
  154. /package/dist/lib/{recipe-usage.js → recipes-usage.js} +0 -0
  155. /package/lib/{recipe-references.ts → recipes-references.ts} +0 -0
@@ -1,7 +1,7 @@
1
1
  /**
2
- * Command-template standard helpers
3
- * Zones: shared utils, local process execution, automation standard
4
- * Owns shell-free command-template splitting, placeholder defaults, composition expansion, executable path expansion, and direct execution
2
+ * Command-template execution standard.
3
+ * Zones: shell-free command parsing, placeholder expansion, local process execution, composition semantics
4
+ * Owns portable command-template parsing, expansion, risk checks, retries, timeouts, and direct execution.
5
5
  */
6
6
  export type CommandTemplateFailureScope = "continue" | "branch" | "root";
7
7
  export interface CommandTemplateActorRecipeContext {
@@ -1,7 +1,7 @@
1
1
  /**
2
- * Command-template standard helpers
3
- * Zones: shared utils, local process execution, automation standard
4
- * Owns shell-free command-template splitting, placeholder defaults, composition expansion, executable path expansion, and direct execution
2
+ * Command-template execution standard.
3
+ * Zones: shell-free command parsing, placeholder expansion, local process execution, composition semantics
4
+ * Owns portable command-template parsing, expansion, risk checks, retries, timeouts, and direct execution.
5
5
  */
6
6
  import { spawn } from "node:child_process";
7
7
  import { homedir } from "node:os";
@@ -4,7 +4,7 @@
4
4
  * Owns registered-tool config loading, normalization, unsupported-shape rejection, and serialization
5
5
  */
6
6
  import type { CommandTemplateValue } from "./command-templates.ts";
7
- import * as RecipeReferences from "./recipe-references.ts";
7
+ import * as RecipesReferences from "./recipes-references.ts";
8
8
  import * as Schema from "./schema.ts";
9
9
  export interface RegisteredTool {
10
10
  name: string;
@@ -12,7 +12,7 @@ export interface RegisteredTool {
12
12
  args: string[];
13
13
  defaults: Record<string, string>;
14
14
  argTypes?: Record<string, Schema.ToolArgType>;
15
- recipe?: RecipeReferences.TemplateRecipeConfig;
15
+ recipe?: RecipesReferences.TemplateRecipeConfig;
16
16
  template?: CommandTemplateValue;
17
17
  storedArgs?: string[];
18
18
  storedDefaults?: Record<string, string>;
@@ -7,7 +7,7 @@ import { existsSync, readFileSync } from "node:fs";
7
7
  import * as CommandTemplates from "./command-templates.js";
8
8
  import { writeJsonAtomic } from "./file-state.js";
9
9
  import { normalizeToolName } from "./identity.js";
10
- import * as RecipeReferences from "./recipe-references.js";
10
+ import * as RecipesReferences from "./recipes-references.js";
11
11
  import * as Schema from "./schema.js";
12
12
  export function serializeTools(source) {
13
13
  const entries = [...source.entries()].sort(([a], [b]) => a.localeCompare(b));
@@ -124,13 +124,13 @@ export function normalizeStoredTool(key, value, reservedToolNames) {
124
124
  : {}),
125
125
  }
126
126
  : undefined;
127
- const isRecipe = RecipeReferences.isRecipeTool(template, recipe);
128
- const recipeTemplate = RecipeReferences.getRecipeTemplate(template);
127
+ const isRecipe = RecipesReferences.isRecipeTool(template, recipe);
128
+ const recipeTemplate = RecipesReferences.getRecipeTemplate(template);
129
129
  const argTemplate = recipeTemplate ?? template;
130
130
  const description = typeof record.description === "string" && record.description.trim()
131
131
  ? record.description.trim()
132
132
  : isRecipe
133
- ? `${recipe?.async === true || RecipeReferences.isAsyncRecipeReference(template) ? "Start async" : "Execute"} template recipe: ${recipe?.name ?? formatTemplateForDescription(template)}`
133
+ ? `${recipe?.async === true || RecipesReferences.isAsyncRecipeReference(template) ? "Start async" : "Execute"} template recipe: ${recipe?.name ?? formatTemplateForDescription(template)}`
134
134
  : `Execute command template: ${formatTemplateForDescription(template)}`;
135
135
  const declarations = Schema.normalizeStoredToolArgDeclarations(record.args, record.defaults);
136
136
  const storedArgs = declarations.provided
@@ -160,7 +160,7 @@ export function normalizeStoredTool(key, value, reservedToolNames) {
160
160
  description,
161
161
  args: isRecipe && storedArgs !== undefined
162
162
  ? Schema.getExplicitToolArgNames(storedArgs)
163
- : RecipeReferences.isRecipeReference(template) && !recipeTemplate
163
+ : RecipesReferences.isRecipeReference(template) && !recipeTemplate
164
164
  ? Schema.getExplicitToolArgNames(storedArgs)
165
165
  : Schema.getToolArgNames(argTemplateConfig),
166
166
  defaults: declarations.defaults,
@@ -1,7 +1,7 @@
1
1
  /**
2
- * Tool output formatting helpers
3
- * Zones: tool execution, output formatting, temp artifacts
4
- * Owns stdout/stderr failure formatting, tail truncation, and full-output temp-file persistence
2
+ * Registered tool execution output.
3
+ * Zones: command execution results, bounded output formatting, temp artifacts
4
+ * Owns stdout/stderr failure formatting, tail truncation, and full-output temp-file persistence.
5
5
  */
6
6
  export interface FormattedOutput {
7
7
  text: string;
@@ -1,7 +1,7 @@
1
1
  /**
2
- * Tool output formatting helpers
3
- * Zones: tool execution, output formatting, temp artifacts
4
- * Owns stdout/stderr failure formatting, tail truncation, and full-output temp-file persistence
2
+ * Registered tool execution output.
3
+ * Zones: command execution results, bounded output formatting, temp artifacts
4
+ * Owns stdout/stderr failure formatting, tail truncation, and full-output temp-file persistence.
5
5
  */
6
6
  import { mkdirSync, mkdtempSync, writeFileSync } from "node:fs";
7
7
  import { join } from "node:path";
@@ -4,7 +4,7 @@
4
4
  * Owns command-template invocation execution and pi tool-result payload formatting
5
5
  */
6
6
  import * as CommandTemplates from "./command-templates.js";
7
- import { formatFailureOutput, formatOutput, formatToolText } from "./output.js";
7
+ import { formatFailureOutput, formatOutput, formatToolText, } from "./execution-output.js";
8
8
  import * as Schema from "./schema.js";
9
9
  const DEFAULT_MAX_PARALLEL_BRANCHES = 64;
10
10
  function textContent(text) {
@@ -1,6 +1,7 @@
1
1
  /**
2
- * Actor inspector TUI previews.
3
- * Zones: terminal actor inspection, room/direct message previews, no-dependency UI formatting
2
+ * Inspector preview rendering.
3
+ * Zones: terminal run inspection, room/direct message previews, no-dependency UI formatting
4
+ * Owns read-only previews and TUI-ready summaries; actor routing stays outside.
4
5
  */
5
6
  export interface ActorInspectorPreview {
6
7
  body_preview?: string;
@@ -1,6 +1,7 @@
1
1
  /**
2
- * Actor inspector TUI previews.
3
- * Zones: terminal actor inspection, room/direct message previews, no-dependency UI formatting
2
+ * Inspector preview rendering.
3
+ * Zones: terminal run inspection, room/direct message previews, no-dependency UI formatting
4
+ * Owns read-only previews and TUI-ready summaries; actor routing stays outside.
4
5
  */
5
6
  import * as fs from "node:fs";
6
7
  import * as path from "node:path";
@@ -1,9 +1,9 @@
1
1
  /**
2
- * Minimal mailbox loop helpers.
2
+ * Mailbox worker loop primitives.
3
3
  * Zones: mailbox-consuming actors, run/branch inbox claiming, handler status transitions
4
- * Owns small reusable primitives for recipe authors; scheduling and task policy stay outside.
4
+ * Owns reusable claim/handle/drain behavior across run and branch inboxes; scheduling and task policy stay outside.
5
5
  */
6
- import { type BranchInboxRecord } from "./actor-rooms.ts";
6
+ import { type BranchInboxRecord } from "./rooms.ts";
7
7
  import { type RunInboxMessage } from "./async-runs.ts";
8
8
  export type MailboxLoopMessage = RunInboxMessage | BranchInboxRecord;
9
9
  export type MailboxLoopTarget = {
@@ -1,9 +1,9 @@
1
1
  /**
2
- * Minimal mailbox loop helpers.
2
+ * Mailbox worker loop primitives.
3
3
  * Zones: mailbox-consuming actors, run/branch inbox claiming, handler status transitions
4
- * Owns small reusable primitives for recipe authors; scheduling and task policy stay outside.
4
+ * Owns reusable claim/handle/drain behavior across run and branch inboxes; scheduling and task policy stay outside.
5
5
  */
6
- import { claimBranchInboxMessage, updateBranchInboxMessageStatus, } from "./actor-rooms.js";
6
+ import { claimBranchInboxMessage, updateBranchInboxMessageStatus, } from "./rooms.js";
7
7
  import { claimRunInboxMessage, updateRunInboxMessageStatus, } from "./async-runs.js";
8
8
  export function isMailboxLoopStopMessage(message) {
9
9
  const type = message && typeof message === "object" && "type" in message
@@ -1,7 +1,7 @@
1
1
  /**
2
- * Actor message protocol helpers.
3
- * Zones: 0.10 draft communication protocol, addressed messages, mailbox metadata
4
- * Owns pure validation/normalization for the semantic message envelope; transport routing stays in adapters.
2
+ * Actor message protocol.
3
+ * Zones: addressed envelopes, address parsing, route normalization
4
+ * Owns pure validation/normalization for semantic actor messages; transport routing stays in adapters.
5
5
  */
6
6
  export type ActorAddressKind = "branch" | "coordinator" | "room" | "run" | "session" | "tool";
7
7
  export interface ActorAddress {
@@ -1,7 +1,7 @@
1
1
  /**
2
- * Actor message protocol helpers.
3
- * Zones: 0.10 draft communication protocol, addressed messages, mailbox metadata
4
- * Owns pure validation/normalization for the semantic message envelope; transport routing stays in adapters.
2
+ * Actor message protocol.
3
+ * Zones: addressed envelopes, address parsing, route normalization
4
+ * Owns pure validation/normalization for semantic actor messages; transport routing stays in adapters.
5
5
  */
6
6
  const ADDRESS_PATTERN = /^[A-Za-z0-9_.-]+$/;
7
7
  const MESSAGE_TYPE_PATTERN = /^[A-Za-z][A-Za-z0-9_.:-]*$/;
@@ -1,9 +1,10 @@
1
1
  /**
2
- * Actor recipe context prompt helpers.
2
+ * Recipe context prompt assembly.
3
3
  * Zones: async runner prompt context, recipe provenance, LLM child launches
4
+ * Owns compact actor recipe context records appended to child-agent prompts.
4
5
  */
5
6
  import type { CommandTemplateActorRecipeContext } from "./command-templates.ts";
6
- import type { TemplateRecipeContextRecord } from "./recipe-references.ts";
7
+ import type { TemplateRecipeContextRecord } from "./recipes-references.ts";
7
8
  export interface MarkedRecipeContextRecord extends TemplateRecipeContextRecord {
8
9
  you_are_here?: true;
9
10
  you_are_here_path?: string;
@@ -1,6 +1,7 @@
1
1
  /**
2
- * Actor recipe context prompt helpers.
2
+ * Recipe context prompt assembly.
3
3
  * Zones: async runner prompt context, recipe provenance, LLM child launches
4
+ * Owns compact actor recipe context records appended to child-agent prompts.
4
5
  */
5
6
  import { basename } from "node:path";
6
7
  function commandName(command) {
@@ -4,7 +4,7 @@
4
4
  * Owns filename identity discovery across prioritized recipe roots
5
5
  */
6
6
  import type { RegisteredTool } from "./config.ts";
7
- import type { TemplateRecipeConfig } from "./recipe-references.ts";
7
+ import type { TemplateRecipeConfig } from "./recipes-references.ts";
8
8
  export interface DiscoveredRecipe {
9
9
  id: string;
10
10
  path: string;
@@ -32,21 +32,21 @@ export interface RecipeIntegrityManifestEntry {
32
32
  disabled: boolean;
33
33
  shadowed: boolean;
34
34
  }
35
- export interface RecipeDiscoveryResult {
35
+ export interface RecipesDiscoveryResult {
36
36
  active: Map<string, DiscoveredRecipe>;
37
37
  entries: DiscoveredRecipe[];
38
38
  diagnostics: string[];
39
39
  }
40
- export interface RecipeDiscoverySource {
40
+ export interface RecipesDiscoverySource {
41
41
  root?: string;
42
42
  file?: string;
43
43
  defaultTool?: boolean;
44
44
  mutableUsage?: boolean;
45
45
  }
46
- export declare function discoverRecipeSources(sources: RecipeDiscoverySource[]): RecipeDiscoveryResult;
47
- export declare function discoverRecipes(roots: string[]): RecipeDiscoveryResult;
48
- export declare function createRecipeIntegrityManifest(result: RecipeDiscoveryResult): RecipeIntegrityManifestEntry[];
49
- export declare function getShadowedLaunchDiagnostic(result: RecipeDiscoveryResult, id: string): Record<string, unknown> | undefined;
46
+ export declare function discoverRecipeSources(sources: RecipesDiscoverySource[]): RecipesDiscoveryResult;
47
+ export declare function discoverRecipes(roots: string[]): RecipesDiscoveryResult;
48
+ export declare function createRecipeIntegrityManifest(result: RecipesDiscoveryResult): RecipeIntegrityManifestEntry[];
49
+ export declare function getShadowedLaunchDiagnostic(result: RecipesDiscoveryResult, id: string): Record<string, unknown> | undefined;
50
50
  export declare function listDraftRecipes(root: string): Array<Record<string, unknown>>;
51
- export declare function summarizeDiscovery(result: RecipeDiscoveryResult): Record<string, unknown>;
51
+ export declare function summarizeDiscovery(result: RecipesDiscoveryResult): Record<string, unknown>;
52
52
  export declare function toRegisteredTool(entry: DiscoveredRecipe): RegisteredTool | undefined;
@@ -7,7 +7,7 @@ import { createHash } from "node:crypto";
7
7
  import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
8
8
  import { join } from "node:path";
9
9
  import * as CommandTemplates from "./command-templates.js";
10
- import * as RecipeReferences from "./recipe-references.js";
10
+ import * as RecipesReferences from "./recipes-references.js";
11
11
  import * as Schema from "./schema.js";
12
12
  function assertToolSafeRepeatConfig(config, argTypes, defaults) {
13
13
  if (typeof config === "string" || config === undefined || config === null)
@@ -47,7 +47,7 @@ function listRecipeFiles(root) {
47
47
  }
48
48
  function getRecipeConfigDiagnostics(file, config) {
49
49
  if (!config) {
50
- const reason = RecipeReferences.diagnoseRawRecipeConfigFailure(file);
50
+ const reason = RecipesReferences.diagnoseRawRecipeConfigFailure(file);
51
51
  return [`Invalid recipe: ${file}${reason ? `: ${reason}` : ""}`];
52
52
  }
53
53
  const commandTemplateConfig = typeof config.template === "object" && config.template !== null
@@ -56,9 +56,9 @@ function getRecipeConfigDiagnostics(file, config) {
56
56
  return CommandTemplates.getCommandTemplateWarnings(commandTemplateConfig).map((warning) => `Recipe ${file}: ${warning}`);
57
57
  }
58
58
  function readDiscoveredRecipe(root, file, priority, defaultTool = false, mutableUsage = false) {
59
- const id = RecipeReferences.getRecipeIdFromPath(file);
59
+ const id = RecipesReferences.getRecipeIdFromPath(file);
60
60
  try {
61
- const config = RecipeReferences.readResolvedRecipeConfig(file);
61
+ const config = RecipesReferences.readResolvedRecipeConfig(file);
62
62
  const invalid = !config;
63
63
  const disabled = config?.disabled === true;
64
64
  return {
@@ -427,8 +427,8 @@ export function getShadowedLaunchDiagnostic(result, id) {
427
427
  }
428
428
  export function listDraftRecipes(root) {
429
429
  return listRecipeFiles(root).map((path) => {
430
- const id = RecipeReferences.getRecipeIdFromPath(path);
431
- const config = RecipeReferences.readRawRecipeConfig(path);
430
+ const id = RecipesReferences.getRecipeIdFromPath(path);
431
+ const config = RecipesReferences.readRawRecipeConfig(path);
432
432
  return {
433
433
  id,
434
434
  path,
@@ -3,8 +3,8 @@
3
3
  * Zones: registry mutations, persistence, runtime activation
4
4
  * Owns register/update/delete validation, persistence, runtime side effects, and result payloads
5
5
  */
6
- import * as Config from "./config.ts";
7
6
  import * as CommandTemplates from "./command-templates.ts";
7
+ import * as Config from "./config.ts";
8
8
  export interface RegisterToolInput {
9
9
  name?: string;
10
10
  description?: string;
@@ -5,12 +5,12 @@
5
5
  */
6
6
  import { existsSync, mkdirSync, unlinkSync } from "node:fs";
7
7
  import { dirname, join } from "node:path";
8
- import * as Identity from "./identity.js";
9
- import * as Output from "./output.js";
10
8
  import * as CommandTemplates from "./command-templates.js";
9
+ import * as ExecutionOutput from "./execution-output.js";
11
10
  import { writeJsonAtomic } from "./file-state.js";
11
+ import * as Identity from "./identity.js";
12
12
  import * as Paths from "./paths.js";
13
- import * as RecipeReferences from "./recipe-references.js";
13
+ import * as RecipesReferences from "./recipes-references.js";
14
14
  import * as Schema from "./schema.js";
15
15
  function textContent(text) {
16
16
  return { type: "text", text };
@@ -19,7 +19,7 @@ function listTools(deps) {
19
19
  const names = [...deps.getTools().keys()].sort();
20
20
  return {
21
21
  content: [
22
- textContent(Output.formatToolText(names.length > 0
22
+ textContent(ExecutionOutput.formatToolText(names.length > 0
23
23
  ? `Registered tools:\n${names.map((name) => `- ${name}`).join("\n")}`
24
24
  : "No registered tools.")),
25
25
  ],
@@ -51,7 +51,7 @@ function deleteTool(name, ctx, deps) {
51
51
  if (!tools.has(name)) {
52
52
  return {
53
53
  content: [
54
- textContent(Output.formatToolText(`Tool "${name}" not found.`)),
54
+ textContent(ExecutionOutput.formatToolText(`Tool "${name}" not found.`)),
55
55
  ],
56
56
  details: { tool: name },
57
57
  };
@@ -64,7 +64,7 @@ function deleteTool(name, ctx, deps) {
64
64
  deps.notify(ctx, `Deleted tool: ${name}`, "info");
65
65
  return {
66
66
  content: [
67
- textContent(Output.formatToolText(`Deleted tool "${name}". Reload to remove it from the complete registry.`)),
67
+ textContent(ExecutionOutput.formatToolText(`Deleted tool "${name}". Reload to remove it from the complete registry.`)),
68
68
  ],
69
69
  details: { config: recipePath, tool: name },
70
70
  };
@@ -79,32 +79,32 @@ function getInputTemplate(value) {
79
79
  template: value,
80
80
  });
81
81
  if (steps.length === 0)
82
- throw new Error(Output.formatToolText("Tool template sequence is empty."));
82
+ throw new Error(ExecutionOutput.formatToolText("Tool template sequence is empty."));
83
83
  return value;
84
84
  }
85
85
  if (value && typeof value === "object") {
86
86
  CommandTemplates.expandCommandTemplateConfigs(value);
87
87
  return value;
88
88
  }
89
- throw new Error(Output.formatToolText("Tool template must be a string, object, or sequence."));
89
+ throw new Error(ExecutionOutput.formatToolText("Tool template must be a string, object, or sequence."));
90
90
  }
91
91
  function buildConfig(name, input, existing) {
92
92
  const explicitArgs = input.args === undefined
93
93
  ? undefined
94
94
  : Schema.parseToolArgDeclarations(input.args);
95
95
  if (explicitArgs?.error)
96
- throw new Error(Output.formatToolText(explicitArgs.error));
96
+ throw new Error(ExecutionOutput.formatToolText(explicitArgs.error));
97
97
  const description = (input.description ?? existing?.description ?? "").trim();
98
98
  if (!description) {
99
- throw new Error(Output.formatToolText("Tool description is required unless deleting."));
99
+ throw new Error(ExecutionOutput.formatToolText("Tool description is required unless deleting."));
100
100
  }
101
101
  const template = getInputTemplate(input.template);
102
102
  if (template === null) {
103
- throw new Error(Output.formatToolText("Tool template cannot be null here."));
103
+ throw new Error(ExecutionOutput.formatToolText("Tool template cannot be null here."));
104
104
  }
105
105
  const finalTemplate = template === undefined || template === "" ? existing?.template : template;
106
106
  if (!finalTemplate) {
107
- throw new Error(Output.formatToolText("Tool template is required."));
107
+ throw new Error(ExecutionOutput.formatToolText("Tool template is required."));
108
108
  }
109
109
  const inputRecipe = typeof input.async === "boolean" ? name : undefined;
110
110
  const recipe = inputRecipe
@@ -127,7 +127,7 @@ function buildConfig(name, input, existing) {
127
127
  ? explicitArgs.declarations
128
128
  : existing?.storedArgs;
129
129
  const storedDefaults = Object.keys(defaults).length > 0 ? defaults : undefined;
130
- const recipeTemplate = RecipeReferences.getRecipeTemplate(finalTemplate);
130
+ const recipeTemplate = RecipesReferences.getRecipeTemplate(finalTemplate);
131
131
  const argTemplate = recipeTemplate ?? finalTemplate;
132
132
  const argTemplateConfig = typeof argTemplate === "object" && !Array.isArray(argTemplate)
133
133
  ? {
@@ -151,10 +151,10 @@ function buildConfig(name, input, existing) {
151
151
  description,
152
152
  template: finalTemplate,
153
153
  ...(recipe ? { recipe } : {}),
154
- args: RecipeReferences.isRecipeTool(finalTemplate, recipe) &&
154
+ args: RecipesReferences.isRecipeTool(finalTemplate, recipe) &&
155
155
  storedArgs !== undefined
156
156
  ? Schema.getExplicitToolArgNames(storedArgs)
157
- : RecipeReferences.isRecipeReference(finalTemplate) && !recipeTemplate
157
+ : RecipesReferences.isRecipeReference(finalTemplate) && !recipeTemplate
158
158
  ? Schema.getExplicitToolArgNames(storedArgs)
159
159
  : Schema.getToolArgNames(argTemplateConfig),
160
160
  defaults,
@@ -169,9 +169,9 @@ export async function executeRegisterTool(params, ctx, deps) {
169
169
  return listTools(deps);
170
170
  const name = Identity.normalizeToolName(input.name);
171
171
  if (!name)
172
- throw new Error(Output.formatToolText("Invalid tool name."));
172
+ throw new Error(ExecutionOutput.formatToolText("Invalid tool name."));
173
173
  if (deps.reservedToolNames.has(name)) {
174
- throw new Error(Output.formatToolText(`Reserved tool name: ${name}`));
174
+ throw new Error(ExecutionOutput.formatToolText(`Reserved tool name: ${name}`));
175
175
  }
176
176
  const templateProvided = Object.hasOwn(input, "template");
177
177
  const template = getInputTemplate(input.template);
@@ -181,12 +181,12 @@ export async function executeRegisterTool(params, ctx, deps) {
181
181
  const existing = tools.get(name);
182
182
  const conflict = deps.getExternalToolConflict(name);
183
183
  if (conflict)
184
- throw new Error(Output.formatToolText(conflict));
184
+ throw new Error(ExecutionOutput.formatToolText(conflict));
185
185
  if (existing && !input.update) {
186
- throw new Error(Output.formatToolText(`Tool "${name}" already registered. Use update=true to overwrite.`));
186
+ throw new Error(ExecutionOutput.formatToolText(`Tool "${name}" already registered. Use update=true to overwrite.`));
187
187
  }
188
188
  if (template === undefined && !existing) {
189
- throw new Error(Output.formatToolText("Tool template is required for new registrations."));
189
+ throw new Error(ExecutionOutput.formatToolText("Tool template is required for new registrations."));
190
190
  }
191
191
  const cfg = buildConfig(name, input, existing);
192
192
  let recipePath;
@@ -194,7 +194,7 @@ export async function executeRegisterTool(params, ctx, deps) {
194
194
  recipePath = persistToolRecipe(deps, cfg);
195
195
  }
196
196
  catch (error) {
197
- throw new Error(Output.formatToolText(`Failed to persist tool recipe: ${error instanceof Error ? error.message : String(error)}`));
197
+ throw new Error(ExecutionOutput.formatToolText(`Failed to persist tool recipe: ${error instanceof Error ? error.message : String(error)}`));
198
198
  }
199
199
  cfg.sourcePath = recipePath;
200
200
  tools.set(name, cfg);
@@ -208,7 +208,7 @@ export async function executeRegisterTool(params, ctx, deps) {
208
208
  : "";
209
209
  return {
210
210
  content: [
211
- textContent(Output.formatToolText(`${existing ? "Updated" : "Registered"} tool "${name}" (args: ${Schema.formatToolArgs(cfg.args)}).${warningText}`)),
211
+ textContent(ExecutionOutput.formatToolText(`${existing ? "Updated" : "Registered"} tool "${name}" (args: ${Schema.formatToolArgs(cfg.args)}).${warningText}`)),
212
212
  ],
213
213
  details: {
214
214
  args: cfg.args,
@@ -1,9 +1,9 @@
1
1
  /**
2
- * Actor room persistence helpers.
3
- * Zones: room timelines, room rosters, cross-branch discovery state
4
- * Owns small file-backed room state; routing policy stays in tools/runtime adapters.
2
+ * Actor room persistence.
3
+ * Zones: room timelines, rosters, branch inboxes, cross-branch discovery state
4
+ * Owns file-backed room and branch-mailbox state; routing policy stays in tools/runtime adapters.
5
5
  */
6
- import type { ActorMessage } from "./actor-messages.ts";
6
+ import type { ActorMessage } from "./messages.ts";
7
7
  export interface RoomMember {
8
8
  address: string;
9
9
  caps?: unknown;
@@ -1,7 +1,7 @@
1
1
  /**
2
- * Actor room persistence helpers.
3
- * Zones: room timelines, room rosters, cross-branch discovery state
4
- * Owns small file-backed room state; routing policy stays in tools/runtime adapters.
2
+ * Actor room persistence.
3
+ * Zones: room timelines, rosters, branch inboxes, cross-branch discovery state
4
+ * Owns file-backed room and branch-mailbox state; routing policy stays in tools/runtime adapters.
5
5
  */
6
6
  import * as fs from "node:fs";
7
7
  import { randomUUID } from "node:crypto";
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Async run artifact declarations and manifest resolution.
3
+ * Owns artifact path template expansion and filesystem-backed artifact metadata.
4
+ */
5
+ export type RunArtifactDeclaration = string | {
6
+ path: string;
7
+ kind?: string;
8
+ media_type?: string;
9
+ required?: boolean;
10
+ };
11
+ export interface RunArtifactManifestEntry {
12
+ exists: boolean;
13
+ kind?: string;
14
+ media_type?: string;
15
+ path: string;
16
+ required?: boolean;
17
+ sha256?: string;
18
+ size?: number;
19
+ }
20
+ export declare function resolveArtifactPaths(artifacts: Record<string, RunArtifactDeclaration> | undefined, values: Record<string, unknown>): Record<string, RunArtifactDeclaration> | undefined;
21
+ export declare function resolveArtifactManifest(artifacts: Record<string, RunArtifactDeclaration> | undefined): Record<string, RunArtifactManifestEntry> | undefined;
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Async run artifact declarations and manifest resolution.
3
+ * Owns artifact path template expansion and filesystem-backed artifact metadata.
4
+ */
5
+ import { createHash } from "node:crypto";
6
+ import { readFileSync } from "node:fs";
7
+ import { substituteCommandTemplateToken } from "./command-templates.js";
8
+ export function resolveArtifactPaths(artifacts, values) {
9
+ if (!artifacts)
10
+ return undefined;
11
+ const resolved = {};
12
+ for (const [key, value] of Object.entries(artifacts)) {
13
+ if (!key.trim())
14
+ continue;
15
+ if (typeof value === "string") {
16
+ resolved[key] = substituteCommandTemplateToken(value, values, `recipe artifacts.${key}`);
17
+ }
18
+ else if (value &&
19
+ typeof value === "object" &&
20
+ typeof value.path === "string") {
21
+ resolved[key] = {
22
+ ...value,
23
+ path: substituteCommandTemplateToken(value.path, values, `recipe artifacts.${key}.path`),
24
+ };
25
+ }
26
+ }
27
+ return Object.keys(resolved).length > 0 ? resolved : undefined;
28
+ }
29
+ export function resolveArtifactManifest(artifacts) {
30
+ if (!artifacts)
31
+ return undefined;
32
+ const manifest = {};
33
+ for (const [name, artifact] of Object.entries(artifacts)) {
34
+ const declaration = typeof artifact === "string" ? { path: artifact } : artifact;
35
+ if (!declaration?.path)
36
+ continue;
37
+ try {
38
+ const content = readFileSync(declaration.path);
39
+ manifest[name] = {
40
+ exists: true,
41
+ ...(declaration.kind ? { kind: declaration.kind } : {}),
42
+ ...(declaration.media_type
43
+ ? { media_type: declaration.media_type }
44
+ : {}),
45
+ path: declaration.path,
46
+ ...(declaration.required !== undefined
47
+ ? { required: declaration.required }
48
+ : {}),
49
+ sha256: createHash("sha256").update(content).digest("hex"),
50
+ size: content.byteLength,
51
+ };
52
+ }
53
+ catch {
54
+ manifest[name] = {
55
+ exists: false,
56
+ ...(declaration.kind ? { kind: declaration.kind } : {}),
57
+ ...(declaration.media_type
58
+ ? { media_type: declaration.media_type }
59
+ : {}),
60
+ path: declaration.path,
61
+ ...(declaration.required !== undefined
62
+ ? { required: declaration.required }
63
+ : {}),
64
+ };
65
+ }
66
+ }
67
+ return Object.keys(manifest).length > 0 ? manifest : undefined;
68
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Async run process control primitives.
3
+ * Owns platform signal planning, owned-process signalling, and terminal control markers.
4
+ */
5
+ export interface RunProcessSignalPlan {
6
+ args?: string[];
7
+ command?: string;
8
+ signalTarget: "processGroup" | "process" | "processTree";
9
+ }
10
+ export declare function getRunProcessSignalPlan(pid: number, signal: NodeJS.Signals, runtimePlatform?: NodeJS.Platform): RunProcessSignalPlan;
11
+ export declare function signalOwnedRunProcess(pid: number, signal: NodeJS.Signals): RunProcessSignalPlan;
12
+ export declare function markTerminalHandled(stateDir: string, details: Record<string, unknown>): void;
13
+ export declare function buildTerminalProgress(existing: Record<string, unknown> | undefined, phase: "cancelled" | "killed"): Record<string, unknown>;