@marcoscale98/pi-extensible-workflows 5.17.0-fork.1 → 5.19.1-fork.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 (80) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/dist/src/agent-execution.js +81 -39
  3. package/dist/src/background-widget.d.ts +5 -0
  4. package/dist/src/background-widget.js +1 -1
  5. package/dist/src/decoders.js +26 -0
  6. package/dist/src/execution.d.ts +4 -2
  7. package/dist/src/execution.js +43 -2
  8. package/dist/src/host-delivery.js +1 -0
  9. package/dist/src/host-recovery.d.ts +5 -2
  10. package/dist/src/host-recovery.js +3 -3
  11. package/dist/src/host-view.d.ts +5 -0
  12. package/dist/src/host-view.js +29 -5
  13. package/dist/src/host.d.ts +2 -2
  14. package/dist/src/host.js +190 -37
  15. package/dist/src/index.js +495 -93
  16. package/dist/src/index.js.map +3 -3
  17. package/dist/src/paths.d.ts +2 -0
  18. package/dist/src/paths.js +2 -0
  19. package/dist/src/registry.js +1 -1
  20. package/dist/src/roles.js +4 -3
  21. package/dist/src/script-tools.d.ts +27 -0
  22. package/dist/src/script-tools.js +87 -0
  23. package/dist/src/settings.d.ts +13 -0
  24. package/dist/src/settings.js +27 -3
  25. package/dist/src/trajectory.d.ts +12 -2
  26. package/dist/src/trajectory.js +30 -8
  27. package/dist/src/types.d.ts +30 -2
  28. package/dist/src/types.js +1 -1
  29. package/dist/src/utils.d.ts +19 -0
  30. package/dist/src/utils.js +30 -0
  31. package/dist/src/validation.d.ts +6 -1
  32. package/dist/src/validation.js +21 -1
  33. package/dist/starter/index.js +0 -2
  34. package/dist/starter/index.js.map +1 -1
  35. package/dist/starter/review-loop.d.ts +0 -13
  36. package/dist/starter/review-loop.js +0 -2
  37. package/dist/subagents/index.js +267 -159
  38. package/dist/subagents/index.js.map +2 -2
  39. package/dist/subagents/src/contracts.d.ts +45 -29
  40. package/dist/subagents/src/contracts.js +18 -7
  41. package/dist/subagents/src/index.d.ts +1 -1
  42. package/dist/subagents/src/index.js +13 -6
  43. package/dist/subagents/src/manager.js +3 -3
  44. package/dist/subagents/src/view.d.ts +1 -0
  45. package/dist/subagents/src/view.js +13 -52
  46. package/dist/trajectory/assets/index.html +27 -5
  47. package/dist/trajectory/index.js +76 -28
  48. package/dist/trajectory/index.js.map +2 -2
  49. package/dist/trajectory/src/assets/index.html +27 -5
  50. package/dist/trajectory/src/index.js +8 -18
  51. package/dist/trajectory/src/server.js +4 -2
  52. package/dist/trajectory/src/server.js.map +2 -2
  53. package/package.json +6 -6
  54. package/skills/pi-extensible-workflows/SKILL.md +2 -0
  55. package/src/agent-execution.ts +77 -41
  56. package/src/background-widget.ts +1 -1
  57. package/src/decoders.ts +20 -0
  58. package/src/execution.ts +41 -4
  59. package/src/host-delivery.ts +1 -0
  60. package/src/host-recovery.ts +8 -7
  61. package/src/host-view.ts +23 -5
  62. package/src/host.ts +173 -35
  63. package/src/paths.ts +3 -0
  64. package/src/registry.ts +1 -1
  65. package/src/roles.ts +4 -3
  66. package/src/script-tools.ts +76 -0
  67. package/src/settings.ts +22 -4
  68. package/src/trajectory.ts +30 -11
  69. package/src/types.ts +11 -4
  70. package/src/utils.ts +28 -0
  71. package/src/validation.ts +19 -1
  72. package/starter/review-loop.ts +0 -2
  73. package/subagents/README.md +2 -2
  74. package/subagents/src/contracts.ts +18 -7
  75. package/subagents/src/index.ts +16 -6
  76. package/subagents/src/manager.ts +3 -3
  77. package/subagents/src/view.ts +13 -50
  78. package/trajectory/src/assets/index.html +27 -5
  79. package/trajectory/src/index.ts +6 -9
  80. package/trajectory/src/server.ts +2 -2
@@ -28,6 +28,7 @@ var ERROR_CODES = [
28
28
  "AGENT_FAILED",
29
29
  "AGENT_RESULT_COLLECTED",
30
30
  "RESULT_INVALID",
31
+ "TOOL_FAILED",
31
32
  "CANCELLED",
32
33
  "WORKER_UNRESPONSIVE",
33
34
  "WORKTREE_FAILED",
@@ -284,6 +285,16 @@ function resolveModelReference(value, aliases = {}, knownModels, settingsPath) {
284
285
  };
285
286
  return resolveReference(value, []);
286
287
  }
288
+ function reachableTools(pi) {
289
+ const undeclared = pi.getAllTools?.().filter(({ exposure }) => exposure === "codemode" || exposure === "deferred").map(({ name }) => name) ?? [];
290
+ return [.../* @__PURE__ */ new Set([...pi.getActiveTools(), ...undeclared])];
291
+ }
292
+ var VIRTUAL_MODEL_PROVIDER = "workflow";
293
+ function physicalModel(spec, aliases = {}, knownModels, settingsPath) {
294
+ if (spec.provider !== VIRTUAL_MODEL_PROVIDER || !modelAliasName(spec.model, aliases)) return spec;
295
+ const target = resolveModelReference(spec.model, aliases, knownModels, settingsPath);
296
+ return spec.thinking === void 0 ? target : { ...target, thinking: spec.thinking };
297
+ }
287
298
  function modelCapability(value, aliases, knownModels, settingsPath) {
288
299
  const parsed = typeof value === "string" ? resolveModelReference(value, aliases, knownModels, settingsPath) : value;
289
300
  return `${parsed.provider}/${parsed.model}`;
@@ -351,6 +362,9 @@ function canonicalPath(path) {
351
362
  return absolute;
352
363
  }
353
364
  }
365
+ function extensionIdentity(path) {
366
+ return path.startsWith("builtin:") ? path : canonicalPath(path);
367
+ }
354
368
  function sameFilesystemPath(left, right) {
355
369
  return canonicalPath(left) === canonicalPath(right);
356
370
  }
@@ -820,10 +834,10 @@ function decodeAgent(value) {
820
834
  const attemptDetails = value.attemptDetails === void 0 ? void 0 : decodeArray(value.attemptDetails, decodeAgentAttempt);
821
835
  const accounting2 = value.accounting === void 0 ? void 0 : decodeAgentAccounting(value.accounting);
822
836
  const toolCalls = value.toolCalls === void 0 ? void 0 : decodeArray(value.toolCalls, decodeAgentToolCall);
823
- const activity2 = value.activity === void 0 ? void 0 : decodeAgentActivity(value.activity);
837
+ const activity = value.activity === void 0 ? void 0 : decodeAgentActivity(value.activity);
824
838
  const lastEventAt = optionalNumber(value.lastEventAt);
825
839
  if (systemPrompt === INVALID_PERSISTED_VALUE || prompt === INVALID_PERSISTED_VALUE || label2 === INVALID_PERSISTED_VALUE || parentId === INVALID_PERSISTED_VALUE || resultPath2 === INVALID_PERSISTED_VALUE || parentBreadcrumb === INVALID_PERSISTED_VALUE || worktreeOwner === INVALID_PERSISTED_VALUE || role === INVALID_PERSISTED_VALUE || requestedModel === INVALID_PERSISTED_VALUE || startedAt === INVALID_PERSISTED_VALUE || durationMs === INVALID_PERSISTED_VALUE || lastEventAt === INVALID_PERSISTED_VALUE || handle === INVALID_PERSISTED_VALUE || continuity === INVALID_PERSISTED_VALUE || handle !== void 0 && !positiveInteger(value.turn)) return void 0;
826
- if (!model || !tools || value.structuralPath !== void 0 && !structuralPath2 || value.attemptDetails !== void 0 && !attemptDetails || value.accounting !== void 0 && !accounting2 || value.toolCalls !== void 0 && !toolCalls || value.activity !== void 0 && !activity2) return void 0;
840
+ if (!model || !tools || value.structuralPath !== void 0 && !structuralPath2 || value.attemptDetails !== void 0 && !attemptDetails || value.accounting !== void 0 && !accounting2 || value.toolCalls !== void 0 && !toolCalls || value.activity !== void 0 && !activity) return void 0;
827
841
  return {
828
842
  ...systemPrompt === void 0 ? {} : { systemPrompt },
829
843
  ...prompt === void 0 ? {} : { prompt },
@@ -849,7 +863,7 @@ function decodeAgent(value) {
849
863
  ...attemptDetails === void 0 ? {} : { attemptDetails },
850
864
  ...accounting2 === void 0 ? {} : { accounting: accounting2 },
851
865
  ...toolCalls === void 0 ? {} : { toolCalls },
852
- ...activity2 === void 0 ? {} : { activity: activity2 },
866
+ ...activity === void 0 ? {} : { activity },
853
867
  ...lastEventAt === void 0 ? {} : { lastEventAt }
854
868
  };
855
869
  }
@@ -897,6 +911,22 @@ function decodeRunEvent(value) {
897
911
  if (timestamp2 === INVALID_PERSISTED_VALUE) return void 0;
898
912
  return { type: value.type, message: value.message, ...timestamp2 === void 0 ? {} : { timestamp: timestamp2 } };
899
913
  }
914
+ function decodeScriptCall(value) {
915
+ if (!object(value) || value.kind !== "shell" && value.kind !== "tool" || typeof value.name !== "string" || typeof value.path !== "string" || !finiteNumber(value.startedAt)) return void 0;
916
+ const shell = value.kind === "shell";
917
+ if (shell && !jsonValue(value.input)) return void 0;
918
+ const inputBytes = shell ? optionalNumber(value.inputBytes) : void 0;
919
+ const phase = optionalString(value.phase);
920
+ const finishedAt = optionalNumber(value.finishedAt);
921
+ let error;
922
+ if (value.error !== void 0) {
923
+ if (shell) error = decodeWorkflowError(value.error);
924
+ else if (object(value.error) && typeof value.error.code === "string") error = { code: isWorkflowErrorCode(value.error.code) ? value.error.code : "INTERNAL_ERROR" };
925
+ if (!error) return void 0;
926
+ }
927
+ if (inputBytes === INVALID_PERSISTED_VALUE || phase === INVALID_PERSISTED_VALUE || finishedAt === INVALID_PERSISTED_VALUE) return void 0;
928
+ return { kind: value.kind, name: value.name, path: value.path, ...shell && jsonValue(value.input) ? { input: value.input } : {}, ...inputBytes === void 0 ? {} : { inputBytes }, ...phase === void 0 ? {} : { phase }, startedAt: value.startedAt, ...finishedAt === void 0 ? {} : { finishedAt }, ...error === void 0 ? {} : { error } };
929
+ }
900
930
  function decodeDelivery(value) {
901
931
  if (!object(value)) return void 0;
902
932
  const mode = value.mode;
@@ -926,6 +956,8 @@ function decodePersistedRun(value, allowLegacyAgentSessions = false) {
926
956
  const budgetEvents = value.budgetEvents === void 0 ? void 0 : decodeArray(value.budgetEvents, decodeBudgetEvent);
927
957
  const events = value.events === void 0 ? void 0 : decodeArray(value.events, decodeRunEvent);
928
958
  const delivery = value.delivery === void 0 ? void 0 : decodeDelivery(value.delivery);
959
+ const scriptCalls = value.scriptCalls === void 0 ? void 0 : decodeArray(value.scriptCalls, decodeScriptCall);
960
+ if (value.scriptCalls !== void 0 && !scriptCalls) return void 0;
929
961
  if (!agentSessions || !agents || parentRunId === INVALID_PERSISTED_VALUE || value.retry !== void 0 && !retry || phase === INVALID_PERSISTED_VALUE || value.phaseHistory !== void 0 && !phaseHistory || phaseHistoryIndex === INVALID_PERSISTED_VALUE || activeShells === INVALID_PERSISTED_VALUE || activeShellStartedAt === INVALID_PERSISTED_VALUE || value.activeShellsByPhase !== void 0 && !activeShellsByPhase || value.error !== void 0 && !error || failedAt === INVALID_PERSISTED_VALUE || value.budget !== void 0 && !budget || budgetVersion === INVALID_PERSISTED_VALUE || value.budgetVersion !== void 0 && !integer(budgetVersion) || value.usage !== void 0 && !usage || value.budgetEvents !== void 0 && !budgetEvents || value.events !== void 0 && !events || value.delivery !== void 0 && !delivery) return void 0;
930
962
  if (value.agentSessions === void 0 && !allowLegacyAgentSessions) return void 0;
931
963
  return {
@@ -944,6 +976,7 @@ function decodePersistedRun(value, allowLegacyAgentSessions = false) {
944
976
  ...activeShells === void 0 ? {} : { activeShells },
945
977
  ...activeShellStartedAt === void 0 ? {} : { activeShellStartedAt },
946
978
  ...activeShellsByPhase === void 0 ? {} : { activeShellsByPhase },
979
+ ...scriptCalls === void 0 ? {} : { scriptCalls },
947
980
  ...error === void 0 ? {} : { error },
948
981
  ...failedAt === void 0 ? {} : { failedAt },
949
982
  ...budget === void 0 ? {} : { budget },
@@ -1952,7 +1985,7 @@ function workflowSettingsPath(agentDir = getAgentDir()) {
1952
1985
  return join3(agentDir, ROLE_DIRECTORY, "settings.json");
1953
1986
  }
1954
1987
  function normalizedResourcePath(value, settingsPath) {
1955
- if (value === "*") return value;
1988
+ if (value === "*" || value.startsWith("builtin:")) return value;
1956
1989
  let expanded = value === "~" ? homedir3() : value.startsWith("~/") || value.startsWith("~\\") ? join3(homedir3(), value.slice(2)) : value;
1957
1990
  if (expanded.startsWith("file://")) expanded = fileURLToPath(expanded);
1958
1991
  const resolved = resolve3(dirname2(settingsPath), expanded);
@@ -2064,7 +2097,7 @@ function parseSettings(path, partial) {
2064
2097
  fail("CONFIG_ERROR", `Invalid workflow settings JSON at ${path}: ${errorText(error)}`);
2065
2098
  }
2066
2099
  if (!object(parsed)) fail("INVALID_SETTINGS", `Workflow settings at ${path} must be an object`);
2067
- const allowed = /* @__PURE__ */ new Set(["concurrency", "modelAliases", "skills", "extensions", "extensionSettings", "tools", "retention", "worktreePostCreateCommand", ...partial ? [] : ["backgroundWidget"]]);
2100
+ const allowed = /* @__PURE__ */ new Set(["concurrency", "modelAliases", "skills", "extensions", "extensionSettings", "tools", "retention", "worktreePostCreateCommand", ...partial ? [] : ["backgroundWidget", "codemodeTools"]]);
2068
2101
  const unknown = Object.keys(parsed).find((key) => !allowed.has(key));
2069
2102
  if (Object.prototype.hasOwnProperty.call(parsed, "disabledAgentResources")) fail("INVALID_SETTINGS", `disabledAgentResources is no longer supported; use skills, extensions, and tools selectors (settings: ${path})`);
2070
2103
  if (unknown) fail("INVALID_SETTINGS", `Unknown workflow setting at ${path}: ${unknown}`);
@@ -2072,6 +2105,8 @@ function parseSettings(path, partial) {
2072
2105
  if (concurrency !== void 0 && (!positiveInteger(concurrency) || concurrency > 16)) fail("INVALID_SETTINGS", `${path}.concurrency must be an integer from 1 to 16`);
2073
2106
  const backgroundWidget = parsed.backgroundWidget === void 0 ? partial ? void 0 : DEFAULT_SETTINGS.backgroundWidget : parsed.backgroundWidget;
2074
2107
  if (backgroundWidget !== void 0 && typeof backgroundWidget !== "boolean") fail("INVALID_SETTINGS", `${path}.backgroundWidget must be a boolean`);
2108
+ const codemodeTools = parsed.codemodeTools;
2109
+ if (codemodeTools !== void 0 && codemodeTools !== "all" && codemodeTools !== "read-only" && codemodeTools !== "none") fail("INVALID_SETTINGS", `${path}.codemodeTools must be "all", "read-only", or "none"`);
2075
2110
  const modelAliases = parsed.modelAliases === void 0 ? void 0 : validateModelAliases(parsed.modelAliases, path);
2076
2111
  const skills = validateSelectorList(parsed.skills, path, "skills");
2077
2112
  const tools = validateSelectorList(parsed.tools, path, "tools");
@@ -2082,6 +2117,7 @@ function parseSettings(path, partial) {
2082
2117
  return Object.freeze({
2083
2118
  ...concurrency === void 0 ? {} : { concurrency },
2084
2119
  ...backgroundWidget === void 0 ? {} : { backgroundWidget },
2120
+ ...codemodeTools === void 0 ? {} : { codemodeTools },
2085
2121
  ...modelAliases === void 0 ? {} : { modelAliases },
2086
2122
  ...skills === void 0 ? {} : { skills },
2087
2123
  ...extensions === void 0 ? {} : { extensions },
@@ -2094,6 +2130,18 @@ function parseSettings(path, partial) {
2094
2130
  function loadSettings(path = workflowSettingsPath()) {
2095
2131
  return parseSettings(path, false);
2096
2132
  }
2133
+ var READ_ONLY_WORKFLOW_TOOLS = /* @__PURE__ */ new Set(["workflow_status", "workflow_catalog", "subagents_inspect"]);
2134
+ function workflowToolExposure(name, codemodeTools) {
2135
+ const readOnly = READ_ONLY_WORKFLOW_TOOLS.has(name);
2136
+ return { ...codemodeTools === "none" || codemodeTools === "read-only" && !readOnly ? { exposure: "model-only" } : {}, ...readOnly ? { annotations: { readOnlyHint: true } } : {} };
2137
+ }
2138
+ function loadCodemodeToolsSetting(agentDir) {
2139
+ try {
2140
+ return loadSettings(workflowSettingsPath(agentDir)).codemodeTools;
2141
+ } catch {
2142
+ return void 0;
2143
+ }
2144
+ }
2097
2145
  function loadSettingsOverrides(path) {
2098
2146
  return parseSettings(path, true);
2099
2147
  }
@@ -2154,7 +2202,7 @@ function resolveAgentResourcePolicy(cwd, projectTrusted, globalSettingsPath = wo
2154
2202
  }
2155
2203
 
2156
2204
  // src/registry.ts
2157
- var RESERVED_GLOBALS = /* @__PURE__ */ new Set(["agent", "shell", "prompt", "checkpoint", "parallel", "pipeline", "phase", "withWorktree", "log", "args", "Promise", "JSON", "Math", "Date", "eval", "Function", "WebAssembly", "process", "require", "module", "exports", "console", "fetch", "XMLHttpRequest", "WebSocket", "performance", "crypto", "setTimeout", "setInterval", "setImmediate", "queueMicrotask", "Intl", "SharedArrayBuffer", "Atomics", "globalThis", "global", "undefined", "NaN", "Infinity", "extensions", "workflow_catalog"]);
2205
+ var RESERVED_GLOBALS = /* @__PURE__ */ new Set(["agent", "shell", "tools", "prompt", "checkpoint", "parallel", "pipeline", "phase", "withWorktree", "log", "args", "Promise", "JSON", "Math", "Date", "eval", "Function", "WebAssembly", "process", "require", "module", "exports", "console", "fetch", "XMLHttpRequest", "WebSocket", "performance", "crypto", "setTimeout", "setInterval", "setImmediate", "queueMicrotask", "Intl", "SharedArrayBuffer", "Atomics", "globalThis", "global", "undefined", "NaN", "Infinity", "extensions", "workflow_catalog"]);
2158
2206
  var IDENTIFIER = /^[A-Za-z_$][\w$]*$/;
2159
2207
  var SEMVER = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
2160
2208
  var PACKAGE_NAME = /^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/;
@@ -2629,7 +2677,7 @@ function loadAgentDefinitions(cwd, agentDir = getAgentDir2(), projectTrusted = t
2629
2677
  function canonicalExtensionSelector(selector, base = process.cwd()) {
2630
2678
  const negated = selector.startsWith("!");
2631
2679
  const body = negated ? selector.slice(1) : selector;
2632
- if (body === "*" || body === "**" || body.startsWith("**/")) return selector;
2680
+ if (body === "*" || body === "**" || body.startsWith("**/") || body.startsWith("builtin:")) return selector;
2633
2681
  const resolved = resolve4(base, body);
2634
2682
  if (resourcePatternHasMagic(body)) return `${negated ? "!" : ""}${resolved}`;
2635
2683
  return `${negated ? "!" : ""}${canonicalPath(resolved)}`;
@@ -2690,7 +2738,7 @@ function resolveRole(name, options) {
2690
2738
  if (outsideRootTool) fail("UNKNOWN_TOOL", `Tool is outside the launching session boundary: ${outsideRootTool}`);
2691
2739
  }
2692
2740
  const selectedSkills = resources.skills === void 0 ? void 0 : selectResourcesByLayers(selectorLayers.skills, resources.skills);
2693
- const extensionResources = resources.extensions?.map((extension2) => canonicalPath(extension2));
2741
+ const extensionResources = resources.extensions?.map((extension2) => extensionIdentity(extension2));
2694
2742
  const selectedExtensions = extensionResources === void 0 ? void 0 : selectResourcesByLayers(selectorLayers.extensions, extensionResources);
2695
2743
  const unmatchedSkills = resources.skills === void 0 ? void 0 : unmatchedResourcePatterns(selectorLayers.skills.flatMap((layer) => layer ?? []), resources.skills);
2696
2744
  const unmatchedExtensions = extensionResources === void 0 ? void 0 : unmatchedResourcePatterns(selectorLayers.extensions.flatMap((layer) => layer ?? []), extensionResources);
@@ -2993,6 +3041,30 @@ const functions = Object.freeze(Object.fromEntries(Object.entries(config.functio
2993
3041
  Object.defineProperty(result, "toJSON", { value() { throw workError("INVALID_METADATA", "Workflow function result is a Promise; await it before serialization"); } });
2994
3042
  return result;
2995
3043
  }])));
3044
+ // tools.<id>(args) runs a Pi session tool through the host. Any identifier resolves, so a resumed run
3045
+ // replays journaled calls even when the tool is gone; the host rejects identifiers it cannot call.
3046
+ // A call is the n-th call with the same arguments in its scope, so replay does not depend on the
3047
+ // order in which concurrent calls start.
3048
+ const NOT_TOOLS = new Set(["then", "toJSON", "toString", "valueOf", "constructor"]);
3049
+ const sortedJson = value => Array.isArray(value) ? value.map(sortedJson) : value && typeof value === "object" ? Object.fromEntries(Object.keys(value).sort().map(key => [key, sortedJson(value[key])])) : value;
3050
+ const toolOccurrences = new Map();
3051
+ const toolCall = id => (...values) => {
3052
+ if (worktreeOwners.getStore()) throw workError("INVALID_METADATA", "tools." + id + " is unavailable inside withWorktree: session tools resolve paths against the session working directory");
3053
+ if (values.length > 1 || values[0] !== undefined && (!values[0] || typeof values[0] !== "object" || Array.isArray(values[0]))) throw workError("INVALID_METADATA", "tools." + id + " takes one arguments object");
3054
+ const args = values[0] === undefined ? {} : values[0];
3055
+ const structuralPath = inheritedAgentPath.getStore() || [];
3056
+ const key = JSON.stringify([structuralPath, id, sortedJson(args)]);
3057
+ const occurrence = (toolOccurrences.get(key) || 0) + 1;
3058
+ toolOccurrences.set(key, occurrence);
3059
+ return guardedResult(rpc("tool", [id, args, { structuralPath: [...structuralPath], occurrence }]), "tool");
3060
+ };
3061
+ const tools = new Proxy(Object.create(null), {
3062
+ get: (_target, key) => typeof key === "string" && !NOT_TOOLS.has(key) ? toolCall(key) : undefined,
3063
+ // Probing would branch on the session that resumed the run; the launch already checks named tools.
3064
+ has: () => { throw workError("INVALID_METADATA", "Workflow scripts cannot probe tools with 'in'; call tools.<name>(...) directly, and the launch checks that the tool exists"); },
3065
+ set: () => false,
3066
+ defineProperty: () => false,
3067
+ });
2996
3068
  const recordEntries = (value, kind) => {
2997
3069
  if (!value || typeof value !== "object" || Array.isArray(value)) throw workError("INVALID_METADATA", kind + " must be a record");
2998
3070
  return Object.entries(value);
@@ -3053,7 +3125,7 @@ const pipeline = async (operationName, items, stages) => {
3053
3125
  return Object.fromEntries(results.map(result => [result.name, result.value]));
3054
3126
  };
3055
3127
  const safeMath = Object.fromEntries(Object.getOwnPropertyNames(Math).filter(name => name !== "random").map(name => [name, Math[name]]));
3056
- const sandbox = { agent, shell, withWorktree: rejectWorktree, prompt, checkpoint, parallel, pipeline, phase, log, args: config.args, Promise, JSON, Math: Object.freeze(safeMath) };
3128
+ const sandbox = { agent, shell, withWorktree: rejectWorktree, prompt, checkpoint, parallel, pipeline, phase, log, tools, args: config.args, Promise, JSON, Math: Object.freeze(safeMath) };
3057
3129
  for (const [name, fn] of Object.entries(functions)) Object.defineProperty(sandbox, name, { value: fn, writable: false, configurable: false });
3058
3130
  for (const name of ["Date","eval","Function","WebAssembly","process","require","module","exports","console","fetch","XMLHttpRequest","WebSocket","performance","crypto","setTimeout","setInterval","setImmediate","queueMicrotask","Intl","SharedArrayBuffer","Atomics"]) sandbox[name] = undefined;
3059
3131
  const context = vm.createContext(sandbox, { codeGeneration: { strings: false, wasm: false } });
@@ -3076,7 +3148,7 @@ import { basename as basename4, dirname as dirname5, join as join6, resolve as r
3076
3148
  import { fileURLToPath as fileURLToPath3 } from "node:url";
3077
3149
  import { Type } from "@earendil-works/pi-ai";
3078
3150
  import { Compile } from "typebox/compile";
3079
- import { createAgentSession, DefaultPackageManager, DefaultResourceLoader, defineTool, getAgentDir as getAgentDir3, ModelRuntime, SessionManager, SettingsManager } from "@earendil-works/pi-coding-agent";
3151
+ import { createAgentSession, createCodemodeExtension, createMcpExtension, createToolSearchExtension, DefaultPackageManager, DefaultResourceLoader, defineTool, getAgentDir as getAgentDir3, ModelRuntime, SessionManager, SettingsManager } from "@earendil-works/pi-coding-agent";
3080
3152
 
3081
3153
  // src/pi-runtime-adapter.ts
3082
3154
  var TURN_START_EVENTS = /* @__PURE__ */ new Set(["turn_start", "turn_started", "turnStarted"]);
@@ -3233,14 +3305,14 @@ function createRuntimeHandoffAdapter(handoff) {
3233
3305
  function createPiRuntimeSessionAdapter(session, handoff, clock = Date.now) {
3234
3306
  const neutralHandoff = createRuntimeHandoffAdapter(handoff);
3235
3307
  const toolCalls = /* @__PURE__ */ new Map();
3236
- let activity2;
3308
+ let activity;
3237
3309
  let streamText = "";
3238
3310
  let lastEventAt;
3239
3311
  let lastReportedEventAt;
3240
3312
  let disposed = false;
3241
3313
  let toolCallsView = [];
3242
3314
  const progressAt = (persist, stateOverride, toolCallsValue3, activityValue2, eventAtValue) => ({ usage: runtimeUsage(session), toolCalls: toolCallsValue3, state: stateOverride ?? stateFromSession(session), ...activityValue2 === void 0 ? {} : { activity: activityValue2 }, ...eventAtValue === void 0 ? {} : { lastEventAt: eventAtValue }, persist });
3243
- const snapshot = (persist) => progressAt(persist, void 0, [...toolCalls.values()], activity2, lastEventAt);
3315
+ const snapshot = (persist) => progressAt(persist, void 0, [...toolCalls.values()], activity, lastEventAt);
3244
3316
  return {
3245
3317
  handoff: neutralHandoff,
3246
3318
  observe(event) {
@@ -3251,7 +3323,7 @@ function createPiRuntimeSessionAdapter(session, handoff, clock = Date.now) {
3251
3323
  const eventState = event.state === void 0 ? void 0 : runtimeState(event.state);
3252
3324
  let report = false;
3253
3325
  let persist = false;
3254
- const previousActivity = activity2;
3326
+ const previousActivity = activity;
3255
3327
  let eventToolCalls = toolCallsView;
3256
3328
  if (event.type === "state_changed") {
3257
3329
  report = true;
@@ -3259,7 +3331,7 @@ function createPiRuntimeSessionAdapter(session, handoff, clock = Date.now) {
3259
3331
  }
3260
3332
  if (event.type === "message_start" && event.message?.role === "assistant") {
3261
3333
  streamText = "";
3262
- activity2 = { kind: "text", text: "" };
3334
+ activity = { kind: "text", text: "" };
3263
3335
  report = true;
3264
3336
  }
3265
3337
  if (event.type === "message_update") {
@@ -3267,14 +3339,14 @@ function createPiRuntimeSessionAdapter(session, handoff, clock = Date.now) {
3267
3339
  if (updateType === "thinking_start" || updateType === "text_start") streamText = "";
3268
3340
  const delta = event.assistantMessageEvent?.delta;
3269
3341
  if ((updateType === "thinking_delta" || updateType === "text_delta") && delta) streamText = `${streamText}${delta}`.replace(/\s+/g, " ").slice(-MAX_ACTIVITY_TEXT_CHARS);
3270
- if (updateType && ["thinking_start", "thinking_delta", "thinking_end"].includes(updateType)) activity2 = { kind: "reasoning", text: streamText };
3271
- else if (updateType && ["text_start", "text_delta", "text_end", "toolcall_start", "toolcall_delta", "toolcall_end"].includes(updateType)) activity2 = { kind: "text", text: streamText };
3272
- report = previousActivity?.kind !== activity2?.kind;
3342
+ if (updateType && ["thinking_start", "thinking_delta", "thinking_end"].includes(updateType)) activity = { kind: "reasoning", text: streamText };
3343
+ else if (updateType && ["text_start", "text_delta", "text_end", "toolcall_start", "toolcall_delta", "toolcall_end"].includes(updateType)) activity = { kind: "text", text: streamText };
3344
+ report = previousActivity?.kind !== activity?.kind;
3273
3345
  }
3274
3346
  if (event.type === "message_end") {
3275
3347
  streamText = "";
3276
- activity2 = void 0;
3277
- report = !sameActivity(previousActivity, activity2);
3348
+ activity = void 0;
3349
+ report = !sameActivity(previousActivity, activity);
3278
3350
  if (event.message?.role === "assistant") {
3279
3351
  persist = true;
3280
3352
  report = true;
@@ -3283,24 +3355,24 @@ function createPiRuntimeSessionAdapter(session, handoff, clock = Date.now) {
3283
3355
  if (event.type === "tool_execution_start" && event.toolCallId && event.toolName) {
3284
3356
  toolCalls.set(event.toolCallId, { id: event.toolCallId, name: event.toolName, state: "running" });
3285
3357
  toolCallsView = [...toolCalls.values()];
3286
- activity2 = { kind: "tool", text: event.toolName };
3358
+ activity = { kind: "tool", text: event.toolName };
3287
3359
  report = true;
3288
3360
  }
3289
3361
  if (event.type === "tool_execution_update" && event.toolName) {
3290
- activity2 = { kind: "tool", text: event.toolName };
3291
- report = !sameActivity(previousActivity, activity2);
3362
+ activity = { kind: "tool", text: event.toolName };
3363
+ report = !sameActivity(previousActivity, activity);
3292
3364
  }
3293
3365
  let removeToolCallId;
3294
3366
  if (event.type === "tool_execution_end" && event.toolCallId && event.toolName) {
3295
3367
  toolCalls.set(event.toolCallId, { id: event.toolCallId, name: event.toolName, state: event.isError ? "failed" : "completed" });
3296
3368
  eventToolCalls = [...toolCalls.values()];
3297
- if (activity2?.kind === "tool" && activity2.text === event.toolName) activity2 = void 0;
3369
+ if (activity?.kind === "tool" && activity.text === event.toolName) activity = void 0;
3298
3370
  report = true;
3299
3371
  removeToolCallId = event.toolCallId;
3300
3372
  }
3301
3373
  if (removeToolCallId === void 0) eventToolCalls = toolCallsView;
3302
3374
  if (!report && (lastReportedEventAt === void 0 || eventAt - lastReportedEventAt >= 1e3)) report = true;
3303
- const eventActivity = activity2;
3375
+ const eventActivity = activity;
3304
3376
  let materialized;
3305
3377
  const result = { event, get progress() {
3306
3378
  return materialized ??= progressAt(persist, eventState, eventToolCalls, eventActivity, eventAt);
@@ -3317,7 +3389,7 @@ function createPiRuntimeSessionAdapter(session, handoff, clock = Date.now) {
3317
3389
  disposed = true;
3318
3390
  toolCalls.clear();
3319
3391
  toolCallsView = [];
3320
- activity2 = void 0;
3392
+ activity = void 0;
3321
3393
  }
3322
3394
  };
3323
3395
  }
@@ -3915,16 +3987,25 @@ function parseModel(value, fallback, aliases = {}, knownModels, settingsPath) {
3915
3987
  function accounting(stats) {
3916
3988
  return { input: stats.tokens.input, output: stats.tokens.output, cacheRead: stats.tokens.cacheRead, cacheWrite: stats.tokens.cacheWrite, cost: stats.cost };
3917
3989
  }
3918
- var extensionDirectory = dirname5(fileURLToPath3(import.meta.url));
3919
- var workflowPackageRoot = basename4(dirname5(extensionDirectory)) === "dist" ? resolve5(extensionDirectory, "../..") : resolve5(extensionDirectory, "..");
3920
- var WORKFLOW_HOST_ENTRIES = /* @__PURE__ */ new Set([
3921
- canonicalPath(resolve5(workflowPackageRoot, "src/index.ts")),
3922
- canonicalPath(resolve5(workflowPackageRoot, "dist/src/index.js")),
3923
- canonicalPath(resolve5(workflowPackageRoot, "starter/index.ts")),
3924
- canonicalPath(resolve5(workflowPackageRoot, "dist/starter/index.js")),
3925
- canonicalPath(resolve5(workflowPackageRoot, "subagents/index.ts")),
3926
- canonicalPath(resolve5(workflowPackageRoot, "dist/subagents/index.js"))
3927
- ]);
3990
+ var WORKFLOW_HOST_ENTRY_PATHS = ["src/index.ts", "dist/src/index.js", "starter/index.ts", "dist/starter/index.js", "subagents/index.ts", "dist/subagents/index.js"];
3991
+ function isWorkflowHostEntry(path) {
3992
+ const entryPath = canonicalPath(path);
3993
+ let packageRoot2 = dirname5(entryPath);
3994
+ while (packageRoot2 !== dirname5(packageRoot2)) {
3995
+ const packageMetadataPath = join6(packageRoot2, "package.json");
3996
+ if (existsSync(packageMetadataPath)) {
3997
+ try {
3998
+ const metadata = JSON.parse(readFileSync4(packageMetadataPath, "utf8"));
3999
+ if (typeof metadata !== "object" || metadata === null || !("name" in metadata) || !isCorePackageName(metadata.name)) return false;
4000
+ return WORKFLOW_HOST_ENTRY_PATHS.some((entry) => canonicalPath(join6(packageRoot2, entry)) === entryPath);
4001
+ } catch {
4002
+ return false;
4003
+ }
4004
+ }
4005
+ packageRoot2 = dirname5(packageRoot2);
4006
+ }
4007
+ return false;
4008
+ }
3928
4009
  var WORKFLOW_DIRECTORY = "pi-extensible-workflows";
3929
4010
  function workflowSystemPromptPath(cwd, agentDir, projectTrusted) {
3930
4011
  const projectPath = join6(cwd, ".pi", WORKFLOW_DIRECTORY, "SYSTEM.md");
@@ -3957,33 +4038,40 @@ function loadPiPackageDirectory() {
3957
4038
  }
3958
4039
  }).catch((error) => ({ error: `could not load @earendil-works/pi-coding-agent package metadata: ${errorText(error)}` }));
3959
4040
  }
3960
- var nativePromptTemplateModule;
3961
- async function loadNativePromptTemplateModule() {
4041
+ var nativeCoreModules = /* @__PURE__ */ new Map();
4042
+ async function loadNativeCoreModule(file, label2) {
3962
4043
  const packageDirectory = await loadPiPackageDirectory();
3963
- let promptTemplatePath;
4044
+ let modulePath;
3964
4045
  if (packageDirectory.directory) {
3965
- const candidate = resolve5(packageDirectory.directory, "dist/core/prompt-templates.js");
3966
- if (existsSync(candidate)) promptTemplatePath = candidate;
4046
+ const candidate = resolve5(packageDirectory.directory, "dist/core", file);
4047
+ if (existsSync(candidate)) modulePath = candidate;
3967
4048
  }
3968
- promptTemplatePath ??= resolve5(dirname5(fileURLToPath3(import.meta.resolve("@earendil-works/pi-coding-agent"))), "core/prompt-templates.js");
4049
+ modulePath ??= resolve5(dirname5(fileURLToPath3(import.meta.resolve("@earendil-works/pi-coding-agent"))), "core", file);
3969
4050
  const packageDirectoryError = packageDirectory.error ? ` Package directory lookup failed: ${packageDirectory.error}` : "";
3970
- return nativePromptTemplateModule ??= import(promptTemplatePath).then((module) => module).catch((error) => {
3971
- throw new Error(`Could not load Pi prompt templates.${packageDirectoryError}`, { cause: error });
3972
- });
4051
+ let loaded = nativeCoreModules.get(file);
4052
+ if (!loaded) {
4053
+ loaded = import(modulePath).catch((error) => {
4054
+ throw new Error(`Could not load Pi ${label2}.${packageDirectoryError}`, { cause: error });
4055
+ });
4056
+ nativeCoreModules.set(file, loaded);
4057
+ }
4058
+ return loaded;
3973
4059
  }
3974
4060
  async function expandPromptTemplateForInspection(text, templates) {
3975
- return (await loadNativePromptTemplateModule()).expandPromptTemplate(text, templates);
4061
+ return (await loadNativeCoreModule("prompt-templates.js", "prompt templates")).expandPromptTemplate(text, templates);
4062
+ }
4063
+ async function buildSystemPromptForInspection(options) {
4064
+ return (await loadNativeCoreModule("system-prompt.js", "system prompt builder")).buildSystemPrompt(options);
3976
4065
  }
3977
4066
  async function preparePiPrompt(native, text) {
3978
4067
  const session = native;
3979
4068
  const diagnostics = [];
3980
4069
  const runner = session._extensionRunner;
3981
- const baseSystemPrompt = typeof session._baseSystemPrompt === "string" ? session._baseSystemPrompt : session.systemPrompt ?? "";
4070
+ const baseSystemPrompt = session.systemPrompt ?? "";
3982
4071
  const baseOptions = session._baseSystemPromptOptions;
3983
4072
  const expandSkillCommand = session._expandSkillCommand;
3984
4073
  const templates = session.promptTemplates;
3985
4074
  if (!runner) diagnostics.push({ type: "error", message: "Pi prompt inspection seam is unavailable: extension runner is missing", source: "Pi session" });
3986
- if (typeof session._baseSystemPrompt !== "string") diagnostics.push({ type: "error", message: "Pi prompt inspection seam is unavailable: base system prompt is missing", source: "Pi session" });
3987
4075
  if (baseOptions === void 0) diagnostics.push({ type: "error", message: "Pi prompt inspection seam is unavailable: base system prompt options are missing", source: "Pi session" });
3988
4076
  if (typeof expandSkillCommand !== "function") diagnostics.push({ type: "error", message: "Pi prompt inspection seam is unavailable: skill expansion is missing", source: "Pi session" });
3989
4077
  if (!Array.isArray(templates)) diagnostics.push({ type: "error", message: "Pi prompt inspection seam is unavailable: prompt templates are missing", source: "Pi session" });
@@ -4008,34 +4096,47 @@ async function preparePiPrompt(native, text) {
4008
4096
  diagnostics.push({ type: "error", message: `Pi prompt template expansion is unavailable: ${errorText(error)}`, source: "Pi session" });
4009
4097
  }
4010
4098
  }
4011
- const result = !inputHandled && runner && baseOptions !== void 0 ? await runner.emitBeforeAgentStart(expandedPrompt, void 0, baseSystemPrompt, baseOptions) : void 0;
4099
+ const result = !inputHandled && runner && baseOptions !== void 0 ? await runner.emitBeforeAgentStart(expandedPrompt, void 0, baseOptions) : void 0;
4012
4100
  const prepared = result;
4013
- return { prompt: text, expandedPrompt, systemPrompt: typeof prepared?.systemPrompt === "string" ? prepared.systemPrompt : baseSystemPrompt, systemPromptOptions: baseOptions, messages: prepared?.messages ?? [], inputHandled, diagnostics };
4101
+ const systemPromptOptions = prepared?.systemPromptOptions ?? baseOptions;
4102
+ const systemPrompt = prepared?.systemPromptOptions === void 0 ? baseSystemPrompt : await buildSystemPromptForInspection(prepared.systemPromptOptions);
4103
+ return { prompt: text, expandedPrompt, systemPrompt, systemPromptOptions, messages: prepared?.messages ?? [], inputHandled, diagnostics };
4014
4104
  } finally {
4015
4105
  unsubscribe?.();
4016
4106
  }
4017
4107
  }
4018
4108
  function flushExtensionProviders(resourceLoader, modelRuntime) {
4019
- const { runtime: runtime2 } = resourceLoader.getExtensions();
4109
+ const { runtime } = resourceLoader.getExtensions();
4020
4110
  const failures = [];
4021
- for (const { name, config } of runtime2.pendingProviderRegistrations) {
4111
+ for (const { name, config } of runtime.pendingProviderRegistrations) {
4022
4112
  try {
4023
4113
  modelRuntime.registerProvider(name, config);
4024
4114
  } catch (error) {
4025
4115
  failures.push(`${name}: ${errorText(error)}`);
4026
4116
  }
4027
4117
  }
4028
- runtime2.pendingProviderRegistrations = [];
4029
- for (const { provider } of runtime2.pendingNativeProviderRegistrations) {
4118
+ runtime.pendingProviderRegistrations = [];
4119
+ for (const { provider } of runtime.pendingNativeProviderRegistrations) {
4030
4120
  try {
4031
4121
  modelRuntime.registerNativeProvider(provider);
4032
4122
  } catch (error) {
4033
4123
  failures.push(`${provider.id || "native provider"}: ${errorText(error)}`);
4034
4124
  }
4035
4125
  }
4036
- runtime2.pendingNativeProviderRegistrations = [];
4126
+ runtime.pendingNativeProviderRegistrations = [];
4037
4127
  return failures;
4038
4128
  }
4129
+ function builtinExtensions() {
4130
+ return [
4131
+ { name: "codemode", factory: createCodemodeExtension(), replaceable: true, builtin: true },
4132
+ { name: "tool-search", factory: createToolSearchExtension(), replaceable: true, builtin: true },
4133
+ { name: "mcp", factory: createMcpExtension(), replaceable: true, builtin: true }
4134
+ ];
4135
+ }
4136
+ var BUILTIN_EXTENSION_PREFIX = "builtin:";
4137
+ function isLlamaModel(model) {
4138
+ return model.provider === "llama.cpp";
4139
+ }
4039
4140
  async function createLocalPiSessionHandle(input, sessionStartEvent) {
4040
4141
  const agentDir = input.agentDir ?? getAgentDir3();
4041
4142
  const systemPromptSource = workflowSystemPromptPath(input.cwd, agentDir, input.resourcePolicy?.projectTrusted ?? true);
@@ -4048,13 +4149,16 @@ async function createLocalPiSessionHandle(input, sessionStartEvent) {
4048
4149
  const tools = [.../* @__PURE__ */ new Set([...input.tools, ...customTools.map(({ name }) => name)])];
4049
4150
  let settingsManager;
4050
4151
  let resourceLoader;
4152
+ const builtins = builtinExtensions();
4153
+ const builtinNames = builtins.flatMap((extension2) => typeof extension2 === "function" ? [] : [extension2.name]);
4154
+ const extensionFactories = [...builtins, ...input.extensionFactories ?? []];
4051
4155
  const policy = input.resourcePolicy;
4052
4156
  if (policy) {
4053
4157
  settingsManager = SettingsManager.create(input.cwd, agentDir, { projectTrusted: false });
4054
4158
  settingsManager.setProjectTrusted(policy.projectTrusted);
4055
- const packageManager = new DefaultPackageManager({ cwd: input.cwd, agentDir, settingsManager });
4159
+ const packageManager = new DefaultPackageManager({ cwd: input.cwd, agentDir, settingsManager, builtinExtensions: builtinNames });
4056
4160
  const resolved = await packageManager.resolve();
4057
- const discoveredExtensions = [...new Set(resolved.extensions.filter(({ enabled, metadata }) => enabled && (policy.projectTrusted || metadata.scope !== "project")).map(({ path }) => canonicalPath(path)))];
4161
+ const discoveredExtensions = [...new Set(resolved.extensions.filter(({ enabled, metadata }) => enabled && (policy.projectTrusted || metadata.scope !== "project")).map(({ path }) => extensionIdentity(path)))];
4058
4162
  const selectorSources = policy.selectorSources;
4059
4163
  const selection = resolveRole(void 0, {
4060
4164
  cwd: input.cwd,
@@ -4062,7 +4166,7 @@ async function createLocalPiSessionHandle(input, sessionStartEvent) {
4062
4166
  resources: { extensions: discoveredExtensions }
4063
4167
  });
4064
4168
  const selectedExtensions = selection.selectedExtensions ?? [];
4065
- const extensionPaths = selectedExtensions.filter((path) => !WORKFLOW_HOST_ENTRIES.has(path));
4169
+ const extensionPaths = selectedExtensions.filter((path) => path.startsWith(BUILTIN_EXTENSION_PREFIX) || !isWorkflowHostEntry(path));
4066
4170
  policy.selectedExtensions = selectedExtensions;
4067
4171
  policy.unmatchedExtensions = selection.unmatchedExtensions ?? [];
4068
4172
  const skillPaths = [...new Set(resolved.skills.filter(({ enabled, metadata }) => enabled && (policy.projectTrusted || metadata.scope !== "project")).map(({ path }) => path))];
@@ -4082,7 +4186,7 @@ async function createLocalPiSessionHandle(input, sessionStartEvent) {
4082
4186
  additionalExtensionPaths: extensionPaths,
4083
4187
  noSkills: true,
4084
4188
  additionalSkillPaths: [.../* @__PURE__ */ new Set([...skillPaths, ...input.additionalSkillPaths ?? []])],
4085
- ...input.extensionFactories?.length ? { extensionFactories: input.extensionFactories } : {},
4189
+ extensionFactories,
4086
4190
  ...contextFilesOverride ? { agentsFilesOverride: contextFilesOverride } : {},
4087
4191
  skillsOverride: (base) => {
4088
4192
  const disabledSkills = updateSkillMatches(base.skills);
@@ -4094,17 +4198,17 @@ async function createLocalPiSessionHandle(input, sessionStartEvent) {
4094
4198
  await resourceLoader.reload();
4095
4199
  } else {
4096
4200
  settingsManager = SettingsManager.create(input.cwd, agentDir, { projectTrusted: true });
4097
- const packageManager = new DefaultPackageManager({ cwd: input.cwd, agentDir, settingsManager });
4201
+ const packageManager = new DefaultPackageManager({ cwd: input.cwd, agentDir, settingsManager, builtinExtensions: builtinNames });
4098
4202
  const resolved = await packageManager.resolve();
4099
- const extensionPaths = [...new Set(resolved.extensions.filter(({ enabled }) => enabled).map(({ path }) => canonicalPath(path)).filter((path) => !WORKFLOW_HOST_ENTRIES.has(path)))];
4100
- resourceLoader = new DefaultResourceLoader({ cwd: input.cwd, agentDir, settingsManager, noExtensions: true, additionalExtensionPaths: extensionPaths, ...input.additionalSkillPaths?.length ? { additionalSkillPaths: [...input.additionalSkillPaths] } : {}, ...input.extensionFactories?.length ? { extensionFactories: input.extensionFactories } : {}, ...contextFilesOverride ? { agentsFilesOverride: contextFilesOverride } : {}, ...systemPromptOptions, ...input.systemPromptAppend ? { appendSystemPromptOverride: (base) => [...base, input.systemPromptAppend ?? ""] } : {} });
4203
+ const extensionPaths = [...new Set(resolved.extensions.filter(({ enabled }) => enabled).map(({ path }) => extensionIdentity(path)).filter((path) => path.startsWith(BUILTIN_EXTENSION_PREFIX) || !isWorkflowHostEntry(path)))];
4204
+ resourceLoader = new DefaultResourceLoader({ cwd: input.cwd, agentDir, settingsManager, noExtensions: true, additionalExtensionPaths: extensionPaths, ...input.additionalSkillPaths?.length ? { additionalSkillPaths: [...input.additionalSkillPaths] } : {}, extensionFactories, ...contextFilesOverride ? { agentsFilesOverride: contextFilesOverride } : {}, ...systemPromptOptions, ...input.systemPromptAppend ? { appendSystemPromptOverride: (base) => [...base, input.systemPromptAppend ?? ""] } : {} });
4101
4205
  await resourceLoader.reload();
4102
4206
  }
4103
4207
  const providerFailures = flushExtensionProviders(resourceLoader, modelRuntime);
4104
4208
  await modelRuntime.refresh({ allowNetwork: false });
4105
4209
  const model = modelRuntime.getModel(input.model.provider, input.model.model);
4106
4210
  if (!model) {
4107
- const because = providerFailures.length > 0 ? ` (provider registration failed \u2014 ${providerFailures.join("; ")})` : "";
4211
+ const because = providerFailures.length > 0 ? ` (provider registration failed \u2014 ${providerFailures.join("; ")})` : isLlamaModel(input.model) ? " (Pi does not expose its built-in llama.cpp provider to extension sessions; declare the llama.cpp server as a provider in models.json and use that model instead)" : "";
4108
4212
  throw new WorkflowError("UNKNOWN_MODEL", `Unknown model: ${input.model.provider}/${input.model.model}${because}`);
4109
4213
  }
4110
4214
  const effectiveSessionStartEvent = input.settings === void 0 && sessionStartEvent === void 0 ? void 0 : { ...sessionStartEvent ?? { type: "session_start", reason: "startup" }, settings: input.settings ?? Object.freeze({}) };
@@ -4129,13 +4233,13 @@ async function createLocalPiSessionHandle(input, sessionStartEvent) {
4129
4233
  await shutdown("quit").catch(() => void 0);
4130
4234
  throw error;
4131
4235
  }
4132
- const resourcePaths = { extensions: resourceLoader.getExtensions().extensions.filter(({ path }) => !path.startsWith("<")).map(({ resolvedPath }) => canonicalPath(resolvedPath)), skills: resourceLoader.getSkills().skills.map(({ filePath }) => canonicalPath(filePath)) };
4236
+ const resourcePaths = { extensions: resourceLoader.getExtensions().extensions.filter(({ path }) => !path.startsWith("<")).map(({ resolvedPath }) => extensionIdentity(resolvedPath)), skills: resourceLoader.getSkills().skills.map(({ filePath }) => canonicalPath(filePath)) };
4133
4237
  const resourceInspection = () => {
4134
4238
  const extensions = resourceLoader.getExtensions();
4135
4239
  const skills = resourceLoader.getSkills();
4136
4240
  const diagnostics = [...extensions.errors.map(({ path, error }) => ({ type: "error", message: error, source: path })), ...skills.diagnostics.map(({ type, path, message }) => ({ type, message, ...path ? { source: path } : {} }))];
4137
4241
  const systemSource = systemPromptSource;
4138
- return { extensions: resourceLoader.getExtensions().extensions.filter(({ path }) => !path.startsWith("<")).map(({ resolvedPath }) => canonicalPath(resolvedPath)), skills: skills.skills.map(({ name }) => name), diagnostics, ...systemSource ? { systemPromptSource: systemSource } : resourceLoader.getSystemPrompt() !== void 0 ? { systemPromptSource: "Pi resource loader" } : {} };
4242
+ return { extensions: resourceLoader.getExtensions().extensions.filter(({ path }) => !path.startsWith("<")).map(({ resolvedPath }) => extensionIdentity(resolvedPath)), skills: skills.skills.map(({ name }) => name), diagnostics, ...systemSource ? { systemPromptSource: systemSource } : resourceLoader.getSystemPrompt() !== void 0 ? { systemPromptSource: "Pi resource loader" } : {} };
4139
4243
  };
4140
4244
  const managedSession = Object.assign(session, {
4141
4245
  getLeafId: () => manager.getLeafId(),
@@ -4776,7 +4880,7 @@ var WorkflowAgentExecutor = class {
4776
4880
  ...options.contextFiles === void 0 ? {} : { contextFiles: options.contextFiles },
4777
4881
  ...options.effectiveTools === void 0 ? {} : { effectiveTools: options.effectiveTools }
4778
4882
  });
4779
- return { model: resolved.model ?? this.root.model, ...resolved.requestedModel === void 0 ? {} : { requestedModel: resolved.requestedModel }, tools: resolved.tools ?? [], ...resolved.overrideSystemPrompt ? { systemPrompt: resolved.prompt } : {}, systemPromptAppend: resolved.overrideSystemPrompt ? "" : resolved.prompt, ...resolved.contextFiles === void 0 ? {} : { contextFiles: resolved.contextFiles } };
4883
+ return { model: physicalModel(resolved.model ?? this.root.model, this.root.modelAliases, this.root.knownModels, this.root.settingsPath), ...resolved.requestedModel === void 0 ? {} : { requestedModel: resolved.requestedModel }, tools: resolved.tools ?? [], ...resolved.overrideSystemPrompt ? { systemPrompt: resolved.prompt } : {}, systemPromptAppend: resolved.overrideSystemPrompt ? "" : resolved.prompt, ...resolved.contextFiles === void 0 ? {} : { contextFiles: resolved.contextFiles } };
4780
4884
  }
4781
4885
  async execute(task, options, signal, customTools = [], setSteer, beforeRetry) {
4782
4886
  const executionSignal = signal ?? this.root.runContext?.signal;
@@ -5172,6 +5276,15 @@ function formatWorkflowRuntime(durationMs) {
5172
5276
  const remainingMinutes = minutes % 60;
5173
5277
  return `${String(hours)}h${remainingMinutes ? ` ${String(remainingMinutes)}m` : ""}`;
5174
5278
  }
5279
+ function textBlock(text) {
5280
+ return {
5281
+ render(width) {
5282
+ return text.split("\n").map((line) => truncateToWidth2(line, Math.max(1, width), "\u2026"));
5283
+ },
5284
+ invalidate() {
5285
+ }
5286
+ };
5287
+ }
5175
5288
  var ANSI_SGR_SOURCE = `${String.fromCharCode(27)}\\[[0-9;]*m`;
5176
5289
  var ANSI_SGR = new RegExp(ANSI_SGR_SOURCE);
5177
5290
  function themeWorkflowProgressStyles(theme) {
@@ -5215,13 +5328,13 @@ function elapsedDurationMs(agent, end) {
5215
5328
  return agent.startedAt === void 0 || !Number.isFinite(agent.startedAt) ? void 0 : Math.max(0, end - agent.startedAt);
5216
5329
  }
5217
5330
  function agentActivityLabel(agent) {
5218
- const activity2 = agent.activity;
5219
- if (activity2?.kind === "reasoning" || activity2?.kind === "text") {
5220
- const name = activity2.kind === "reasoning" ? "reasoning" : "responding";
5221
- const text = sanitizeDisplayText(activity2.text);
5331
+ const activity = agent.activity;
5332
+ if (activity?.kind === "reasoning" || activity?.kind === "text") {
5333
+ const name = activity.kind === "reasoning" ? "reasoning" : "responding";
5334
+ const text = sanitizeDisplayText(activity.text);
5222
5335
  return text && text !== name ? `${name} \xB7 ${text}` : name;
5223
5336
  }
5224
- if (activity2?.kind === "tool") return sanitizeDisplayText(activity2.text);
5337
+ if (activity?.kind === "tool") return sanitizeDisplayText(activity.text);
5225
5338
  return sanitizeDisplayText([...agent.toolCalls ?? []].reverse().find(({ state }) => state === "running")?.name ?? "");
5226
5339
  }
5227
5340
  function formatAccountingValue(value) {
@@ -5397,7 +5510,8 @@ var SUBAGENTS_RUN_PARAMETERS = Type2.Object({
5397
5510
  timeoutMs: Type2.Optional(Type2.Union([Type2.Integer({ minimum: 1, description: "Optional execution timeout in milliseconds" }), Type2.Null()]))
5398
5511
  }, { additionalProperties: false });
5399
5512
  var SUBAGENTS_INSPECT_PARAMETERS = Type2.Object({
5400
- id: Type2.Optional(Type2.String({ description: "Subagent ID; omit to list ordered run summaries" }))
5513
+ id: Type2.Optional(Type2.String({ description: "Subagent ID; omit to list ordered run summaries" })),
5514
+ scope: Type2.Optional(Type2.Union([Type2.Literal("session"), Type2.Literal("all")], { description: "List scope when id is omitted: session (default) lists runs from the current Pi session; all lists every stored run" }))
5401
5515
  }, { additionalProperties: false });
5402
5516
  var SUBAGENTS_ID_PARAMETERS = Type2.Object({
5403
5517
  id: Type2.String({ description: "Subagent ID" })
@@ -5412,13 +5526,21 @@ var SUBAGENTS_STOP_PARAMETERS = Type2.Object({
5412
5526
  var SUBAGENTS_RETRY_PARAMETERS = Type2.Object({
5413
5527
  id: Type2.String({ description: "Failed or stopped subagent ID to retry" })
5414
5528
  }, { additionalProperties: false });
5415
- var SUBAGENTS_TOOL_SCHEMAS = {
5416
- subagents_run: SUBAGENTS_RUN_PARAMETERS,
5417
- subagents_inspect: SUBAGENTS_INSPECT_PARAMETERS,
5418
- subagents_steer: SUBAGENTS_STEER_PARAMETERS,
5419
- subagents_stop: SUBAGENTS_STOP_PARAMETERS,
5420
- subagents_retry: SUBAGENTS_RETRY_PARAMETERS
5421
- };
5529
+ var SUBAGENT_STATUS_OUTPUT = Type2.Object({
5530
+ id: Type2.String(),
5531
+ state: Type2.String(),
5532
+ sessionId: Type2.Optional(Type2.String()),
5533
+ startedAt: Type2.Optional(Type2.Number()),
5534
+ finishedAt: Type2.Optional(Type2.Number()),
5535
+ attempts: Type2.Optional(Type2.Number()),
5536
+ attemptDetails: Type2.Optional(Type2.Array(Type2.Unknown())),
5537
+ worktree: Type2.Optional(Type2.Object({ path: Type2.String(), branch: Type2.String() })),
5538
+ error: Type2.Optional(Type2.Object({ code: Type2.String(), message: Type2.String() })),
5539
+ progress: Type2.Optional(Type2.Unknown()),
5540
+ value: Type2.Optional(Type2.Unknown())
5541
+ });
5542
+ var SUBAGENTS_INSPECT_OUTPUT = Type2.Union([SUBAGENT_STATUS_OUTPUT, Type2.Array(Type2.Object({ id: Type2.String(), state: Type2.String() }))]);
5543
+ var SUBAGENTS_STEER_OUTPUT = Type2.Object({ id: Type2.String(), accepted: Type2.Boolean() });
5422
5544
  function normalizeSubagentRunRequest(value) {
5423
5545
  if (!Value2.Check(SUBAGENTS_RUN_PARAMETERS, value)) throw new WorkflowError("INVALID_METADATA", "Invalid subagents_run parameters");
5424
5546
  if (typeof value.worktree === "string" && !value.worktree.trim()) throw new WorkflowError("INVALID_METADATA", "worktree name must be a non-empty string");
@@ -5510,8 +5632,8 @@ function progressValue(value) {
5510
5632
  const accounting2 = accountingValue(record2.accounting);
5511
5633
  const toolCalls = toolCallsValue(record2.toolCalls);
5512
5634
  if (!accounting2 || !toolCalls) return void 0;
5513
- const activity2 = record2.activity === void 0 ? void 0 : activityValue(record2.activity);
5514
- if (record2.activity !== void 0 && activity2 === void 0) return void 0;
5635
+ const activity = record2.activity === void 0 ? void 0 : activityValue(record2.activity);
5636
+ if (record2.activity !== void 0 && activity === void 0) return void 0;
5515
5637
  const rawState = record2.state;
5516
5638
  let state;
5517
5639
  if (rawState !== void 0) {
@@ -5525,16 +5647,16 @@ function progressValue(value) {
5525
5647
  }
5526
5648
  const lastEventAt = record2.lastEventAt;
5527
5649
  if (lastEventAt !== void 0 && !nonnegativeInteger(lastEventAt)) return void 0;
5528
- return { accounting: accounting2, toolCalls, ...state === void 0 ? {} : { state }, ...activity2 === void 0 ? {} : { activity: activity2 }, ...lastEventAt === void 0 ? {} : { lastEventAt } };
5650
+ return { accounting: accounting2, toolCalls, ...state === void 0 ? {} : { state }, ...activity === void 0 ? {} : { activity }, ...lastEventAt === void 0 ? {} : { lastEventAt } };
5529
5651
  }
5530
5652
  function legacyProgressValue(record2) {
5531
5653
  const accounting2 = legacyAccountingValue(record2);
5532
5654
  const toolCalls = record2.toolCalls === void 0 ? [] : toolCallsValue(record2.toolCalls);
5533
5655
  if (!accounting2 || !toolCalls) return void 0;
5534
- const activity2 = record2.activity === void 0 ? void 0 : activityValue(record2.activity);
5656
+ const activity = record2.activity === void 0 ? void 0 : activityValue(record2.activity);
5535
5657
  const lastEventAt = record2.lastEventAt;
5536
- if (record2.activity !== void 0 && activity2 === void 0 || lastEventAt !== void 0 && !nonnegativeInteger(lastEventAt)) return void 0;
5537
- return { accounting: accounting2, toolCalls, ...activity2 === void 0 ? {} : { activity: activity2 }, ...lastEventAt === void 0 ? {} : { lastEventAt } };
5658
+ if (record2.activity !== void 0 && activity === void 0 || lastEventAt !== void 0 && !nonnegativeInteger(lastEventAt)) return void 0;
5659
+ return { accounting: accounting2, toolCalls, ...activity === void 0 ? {} : { activity }, ...lastEventAt === void 0 ? {} : { lastEventAt } };
5538
5660
  }
5539
5661
  function attemptValue(value) {
5540
5662
  const record2 = objectValue(value);
@@ -5618,6 +5740,20 @@ var WORKFLOW_TOOL_PARAMETERS = Type3.Object({
5618
5740
  }, { additionalProperties: false });
5619
5741
  var WORKFLOW_STATUS_PARAMETERS = Type3.Object({ runId: Type3.String({ description: "Workflow run ID visible in the current project" }) }, { additionalProperties: false });
5620
5742
  var WORKFLOW_RETRY_PARAMETERS = Type3.Object({ runId: Type3.String({ description: "Explicit failed workflow run ID" }), expectedState: Type3.Optional(Type3.String({ description: "Persisted source state observed before recovery" })), foreground: Type3.Optional(Type3.Boolean({ description: "Override the source launch mode for this recovery" })) });
5743
+ var WORKFLOW_ERROR_OUTPUT = Type3.Object({ code: Type3.String(), message: Type3.String() });
5744
+ var WORKFLOW_LAUNCH_OUTPUT = Type3.Object({ runId: Type3.String(), state: Type3.String(), detached: Type3.Optional(Type3.Boolean()), value: Type3.Optional(Type3.Unknown()) });
5745
+ var WORKFLOW_STATUS_OUTPUT = Type3.Object({ runId: Type3.String(), workflowName: Type3.String(), state: Type3.String(), error: Type3.Optional(WORKFLOW_ERROR_OUTPUT), failedAt: Type3.Optional(Type3.String()), budget: Type3.Optional(Type3.Unknown()), usage: Type3.Optional(Type3.Unknown()), phase: Type3.Optional(Type3.String()), delivery: Type3.Optional(Type3.Object({ mode: Type3.String(), state: Type3.String() })), agents: Type3.Array(Type3.Object({ id: Type3.String(), label: Type3.Optional(Type3.String()), path: Type3.String(), state: Type3.String(), lastEventAt: Type3.Optional(Type3.Number()), accounting: Type3.Optional(Type3.Unknown()) })) });
5746
+ var WORKFLOW_STOP_OUTPUT = Type3.Object({ runId: Type3.String(), state: Type3.String(), stopped: Type3.Boolean(), reason: Type3.Optional(Type3.String()) });
5747
+ var WORKFLOW_RECOVERY_OUTPUT = Type3.Object({ state: Type3.String(), runId: Type3.Optional(Type3.String()), parentRunId: Type3.Optional(Type3.String()), proposalId: Type3.Optional(Type3.String()), value: Type3.Optional(Type3.Unknown()) });
5748
+ var WORKFLOW_RESPOND_OUTPUT = Type3.Object({ state: Type3.String(), approved: Type3.Boolean(), reason: Type3.String(), accepted: Type3.Optional(Type3.Boolean()), runId: Type3.Optional(Type3.String()), value: Type3.Optional(Type3.Unknown()) });
5749
+ var WORKFLOW_CATALOG_ALIAS_OUTPUT = Type3.Object({ name: Type3.String(), kind: Type3.String(), provenance: Type3.String(), version: Type3.Optional(Type3.String()), headline: Type3.Optional(Type3.String()) });
5750
+ var WORKFLOW_CATALOG_OUTPUT = Type3.Union([
5751
+ Type3.Object({ functions: Type3.Array(Type3.Object({ name: Type3.String(), description: Type3.String(), input: Type3.Unknown() })), modelAliasEntries: Type3.Optional(Type3.Array(WORKFLOW_CATALOG_ALIAS_OUTPUT)), settings: Type3.Optional(Type3.Unknown()) }),
5752
+ Type3.Object({ name: Type3.String(), version: Type3.String(), headline: Type3.String(), description: Type3.String(), input: Type3.Unknown(), output: Type3.Unknown() }),
5753
+ WORKFLOW_CATALOG_ALIAS_OUTPUT,
5754
+ Type3.Object({ error: Type3.Object({ code: Type3.String(), name: Type3.String(), message: Type3.String() }) })
5755
+ ]);
5756
+ var SCRIPT_CALL_TEXT_LIMIT_BYTES = 16 * 1024;
5621
5757
 
5622
5758
  // subagents/src/manager.ts
5623
5759
  import { randomUUID as randomUUID3 } from "node:crypto";
@@ -6203,8 +6339,8 @@ function isPreparedSession(value) {
6203
6339
  const textFields = ["initialPrompt", "agentDir", "systemPromptPath", "systemPromptAppend", "piRuntimeError"];
6204
6340
  if (textFields.some((field) => record2[field] !== void 0 && typeof record2[field] !== "string")) return false;
6205
6341
  if (record2.systemPrompt !== void 0 && (typeof record2.systemPrompt !== "string" || record2.systemPrompt.length > SUBAGENT_SYSTEM_PROMPT_LIMIT)) return false;
6206
- const runtime2 = recordValue(record2.piRuntime);
6207
- if (record2.piRuntime !== void 0 && (!runtime2 || typeof runtime2.executable !== "string" || !runtime2.executable.trim() || runtime2.entrypoint !== void 0 && (typeof runtime2.entrypoint !== "string" || !runtime2.entrypoint.trim()))) return false;
6342
+ const runtime = recordValue(record2.piRuntime);
6343
+ if (record2.piRuntime !== void 0 && (!runtime || typeof runtime.executable !== "string" || !runtime.executable.trim() || runtime.entrypoint !== void 0 && (typeof runtime.entrypoint !== "string" || !runtime.entrypoint.trim()))) return false;
6208
6344
  return true;
6209
6345
  }
6210
6346
  function isLiveSessionHandoff(value) {
@@ -6238,19 +6374,19 @@ function progressValue2(value) {
6238
6374
  const toolCalls = toolCallsValue2(record2.toolCalls);
6239
6375
  const state = record2.state === void 0 ? void 0 : sessionStateValue(record2.state);
6240
6376
  if (!accounting2 || !toolCalls || record2.state !== void 0 && state === void 0) return void 0;
6241
- const activity2 = record2.activity === void 0 ? void 0 : activityValue(record2.activity);
6242
- if (record2.activity !== void 0 && activity2 === void 0) return void 0;
6377
+ const activity = record2.activity === void 0 ? void 0 : activityValue(record2.activity);
6378
+ if (record2.activity !== void 0 && activity === void 0) return void 0;
6243
6379
  if (record2.lastEventAt !== void 0 && (!Number.isSafeInteger(record2.lastEventAt) || record2.lastEventAt < 0)) return void 0;
6244
- return { accounting: accounting2, toolCalls, ...state === void 0 ? {} : { state }, ...activity2 === void 0 ? {} : { activity: activity2 }, ...record2.lastEventAt === void 0 ? {} : { lastEventAt: record2.lastEventAt } };
6380
+ return { accounting: accounting2, toolCalls, ...state === void 0 ? {} : { state }, ...activity === void 0 ? {} : { activity }, ...record2.lastEventAt === void 0 ? {} : { lastEventAt: record2.lastEventAt } };
6245
6381
  }
6246
6382
  function legacyProgressValue2(record2) {
6247
6383
  const accounting2 = legacyAccountingValue(record2);
6248
6384
  const toolCalls = record2.toolCalls === void 0 ? [] : toolCallsValue2(record2.toolCalls);
6249
6385
  if (!accounting2 || !toolCalls) return void 0;
6250
- const activity2 = record2.activity === void 0 ? void 0 : activityValue(record2.activity);
6251
- if (record2.activity !== void 0 && activity2 === void 0) return void 0;
6386
+ const activity = record2.activity === void 0 ? void 0 : activityValue(record2.activity);
6387
+ if (record2.activity !== void 0 && activity === void 0) return void 0;
6252
6388
  if (record2.lastEventAt !== void 0 && (!Number.isSafeInteger(record2.lastEventAt) || record2.lastEventAt < 0)) return void 0;
6253
- return { accounting: accounting2, toolCalls, ...activity2 === void 0 ? {} : { activity: activity2 }, ...record2.lastEventAt === void 0 ? {} : { lastEventAt: record2.lastEventAt } };
6389
+ return { accounting: accounting2, toolCalls, ...activity === void 0 ? {} : { activity }, ...record2.lastEventAt === void 0 ? {} : { lastEventAt: record2.lastEventAt } };
6254
6390
  }
6255
6391
  function worktreeContextValue(value) {
6256
6392
  if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
@@ -6703,9 +6839,9 @@ var PersistentSubagentManager = class {
6703
6839
  }
6704
6840
  return inspection;
6705
6841
  }
6706
- return this.inspectList();
6842
+ return this.inspectList(request.scope === "all" ? void 0 : context.extensionContext.sessionManager.getSessionId());
6707
6843
  }
6708
- async inspectList() {
6844
+ async inspectList(sessionId) {
6709
6845
  const root = storageDirectory(this.dependencies);
6710
6846
  await secureDirectory(root);
6711
6847
  const entries = await readdir3(root, { withFileTypes: true });
@@ -6716,7 +6852,7 @@ var PersistentSubagentManager = class {
6716
6852
  try {
6717
6853
  const active = this.activeRuns.get(entry.name);
6718
6854
  const status = publicStatus(active ? persistedStatus(active) : this.terminalSummaries.get(entry.name) ?? await loadPersistedStatus(root, entry.name, false));
6719
- if (status.startedAt === void 0) continue;
6855
+ if (status.startedAt === void 0 || sessionId !== void 0 && status.sessionId !== sessionId) continue;
6720
6856
  statuses.push({ status, startedAt: status.startedAt });
6721
6857
  } catch (error) {
6722
6858
  if (error instanceof WorkflowError && (error.code === "RUN_NOT_FOUND" || error instanceof InvalidPersistedSubagentStatusError)) continue;
@@ -7228,8 +7364,8 @@ function pickerLabels(entries) {
7228
7364
  const name = names[index] ?? "";
7229
7365
  const model = status.progress?.state?.model;
7230
7366
  const cost = formatCost(status.progress?.accounting.cost);
7231
- const runtime2 = status.startedAt === void 0 ? "" : ` runtime=${formatWorkflowRuntime((status.finishedAt ?? Date.now()) - status.startedAt)}`;
7232
- return `${runStateGlyph(status.state, "\u2826")} ${name} ${status.state}${model ? ` ${boundedText(model.model, 256)}${model.thinking ? `:${model.thinking}` : ""}` : ""}${cost ? ` ${cost}` : ""}${runtime2}`;
7367
+ const runtime = status.startedAt === void 0 ? "" : ` runtime=${formatWorkflowRuntime((status.finishedAt ?? Date.now()) - status.startedAt)}`;
7368
+ return `${runStateGlyph(status.state, "\u2826")} ${name} ${status.state}${model ? ` ${boundedText(model.model, 256)}${model.thinking ? `:${model.thinking}` : ""}` : ""}${cost ? ` ${cost}` : ""}${runtime}`;
7233
7369
  });
7234
7370
  }
7235
7371
  function boundedText(value, limit = MAX_DETAIL_TEXT) {
@@ -7253,7 +7389,7 @@ function detailPresentation(inspection) {
7253
7389
  const { status, request } = inspection.entry;
7254
7390
  const attempt = latestAttempt(status);
7255
7391
  const state = status.progress?.state;
7256
- const activity2 = status.progress?.activity;
7392
+ const activity = status.progress?.activity;
7257
7393
  const model = state?.model ?? attempt?.setup.model;
7258
7394
  const tools = state?.tools ?? attempt?.setup.tools;
7259
7395
  const lastEventAt = status.progress?.lastEventAt;
@@ -7263,7 +7399,7 @@ function detailPresentation(inspection) {
7263
7399
  const error = status.error ?? attempt?.error;
7264
7400
  return {
7265
7401
  state: status.state,
7266
- ...activity2 === void 0 ? {} : { activity: { kind: activity2.kind, text: boundedText(activity2.text) } },
7402
+ ...activity === void 0 ? {} : { activity: { kind: activity.kind, text: boundedText(activity.text) } },
7267
7403
  ...lastEventAt === void 0 ? {} : { lastEventAt },
7268
7404
  ...model === void 0 ? {} : { model: { provider: boundedText(model.provider, 256), model: boundedText(model.model, 256), ...model.thinking === void 0 ? {} : { thinking: model.thinking } } },
7269
7405
  ...role === "none" ? {} : { role: boundedText(role, 256) },
@@ -7843,15 +7979,6 @@ var TERMINAL_STATES = /* @__PURE__ */ new Set(["completed", "failed", "stopped"]
7843
7979
  var MAX_INSPECT_VALUE_CHARS = 4e3;
7844
7980
  var MAX_INSPECT_TOOL_CALLS = 32;
7845
7981
  var MAX_BACKGROUND_WIDGET_ROWS = 10;
7846
- function textBlock2(text) {
7847
- return {
7848
- render(width) {
7849
- return text.split("\n").map((line) => truncateToWidth4(line, Math.max(1, width), "\u2026"));
7850
- },
7851
- invalidate() {
7852
- }
7853
- };
7854
- }
7855
7982
  function roleName(value) {
7856
7983
  if (typeof value === "string") return value.trim() || void 0;
7857
7984
  if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
@@ -7893,17 +8020,6 @@ function statusValue2(value) {
7893
8020
  if (typeof record2.id !== "string" || record2.state !== "running" && record2.state !== "completed" && record2.state !== "failed" && record2.state !== "stopped") return void 0;
7894
8021
  return value;
7895
8022
  }
7896
- function runtime(startedAt, finishedAt, now) {
7897
- if (startedAt === void 0) return "";
7898
- const seconds = Math.max(0, Math.floor(((finishedAt ?? now) - startedAt) / 1e3));
7899
- if (seconds < 60) return `${String(seconds)}s`;
7900
- const minutes = Math.floor(seconds / 60);
7901
- const remainingSeconds = seconds % 60;
7902
- if (minutes < 60) return `${String(minutes)}m${remainingSeconds ? ` ${String(remainingSeconds)}s` : ""}`;
7903
- const hours = Math.floor(minutes / 60);
7904
- const remainingMinutes = minutes % 60;
7905
- return `${String(hours)}h${remainingMinutes ? ` ${String(remainingMinutes)}m` : ""}`;
7906
- }
7907
8023
  function stateGlyph(state, spinner2) {
7908
8024
  if (state === "running") return spinner2;
7909
8025
  return state === "completed" ? "\u2713" : "\u2717";
@@ -7912,23 +8028,6 @@ function stateColor(state) {
7912
8028
  if (state === "running") return "accent";
7913
8029
  return state === "completed" ? "success" : "error";
7914
8030
  }
7915
- function activity(status) {
7916
- if (status.state !== "running") return void 0;
7917
- const current = status.progress?.activity;
7918
- if (current?.kind === "reasoning" || current?.kind === "text") {
7919
- const name = current.kind === "reasoning" ? "reasoning" : "responding";
7920
- const text = sanitizeDisplayText(current.text);
7921
- return text && text !== name ? `${name} \xB7 ${text}` : name;
7922
- }
7923
- if (current?.kind === "tool") return sanitizeDisplayText(current.text);
7924
- return sanitizeDisplayText([...status.progress?.toolCalls ?? []].reverse().find(({ state }) => state === "running")?.name ?? "");
7925
- }
7926
- function stalledDuration2(status, now) {
7927
- const lastEventAt = status.progress?.lastEventAt;
7928
- if (status.state !== "running" || lastEventAt === void 0 || !Number.isFinite(lastEventAt)) return void 0;
7929
- const duration = now - lastEventAt;
7930
- return duration >= WORKFLOW_AGENT_STALL_THRESHOLD_MS ? duration : void 0;
7931
- }
7932
8031
  function usageStats(status) {
7933
8032
  const value = status.progress?.accounting;
7934
8033
  return value ? [formatTokens(value.input + value.output), formatCost(value.cost)].filter(Boolean).join(" \xB7 ") : "";
@@ -7954,15 +8053,15 @@ function boundedValue(value) {
7954
8053
  }
7955
8054
  function formatSubagentProgress(status, args, theme, spinner2, now, expanded) {
7956
8055
  const color = stateColor(status.state);
7957
- const elapsed = runtime(status.startedAt, status.finishedAt, now);
8056
+ const elapsed = status.startedAt === void 0 ? "" : formatWorkflowRuntime((status.finishedAt ?? now) - status.startedAt);
7958
8057
  const metadata = requestMetadata(args, args.id === void 0);
7959
8058
  const stats = usageStats(status);
7960
8059
  const lines = [
7961
- `${theme.fg(color, stateGlyph(status.state, spinner2))} ${theme.bold(theme.fg("accent", `Subagent: ${label({ ...args, id: status.id })}`))} ${theme.fg(color, `[${status.state}]`)}${metadata ? ` ${theme.fg("dim", metadata)}` : ""}${stats ? ` ${stats}` : ""}${elapsed ? ` runtime=${elapsed}` : ""}`
8060
+ `${theme.fg(color, stateGlyph(status.state, "\u25CF"))} ${theme.bold(theme.fg("accent", `Subagent: ${label({ ...args, id: status.id })}`))} ${theme.fg(color, `[${status.state}]`)}${metadata ? ` ${theme.fg("dim", metadata)}` : ""}${stats ? ` ${stats}` : ""}${elapsed ? ` runtime=${elapsed}` : ""}`
7962
8061
  ];
7963
- const current = activity(status);
7964
- const stalled = stalledDuration2(status, now);
7965
- if (current) lines.push(` ${theme.fg("accent", spinner2)} ${theme.fg("dim", current)}${stalled === void 0 ? "" : ` ${theme.fg("warning", `- stalled? ${formatStalledDuration(stalled)}`)}`}`);
8062
+ const current = status.state === "running" ? agentActivityLabel(status.progress ?? {}) : void 0;
8063
+ const stalled = stalledDuration({ ...status.progress, state: status.state }, now);
8064
+ if (current || status.state === "running") lines.push(` ${theme.fg("accent", spinner2)}${current ? ` ${theme.fg("dim", current)}` : ""}${stalled === void 0 ? "" : ` ${theme.fg("warning", `- stalled? ${formatStalledDuration(stalled)}`)}`}`);
7966
8065
  else if (stalled !== void 0) lines.push(` ${theme.fg("warning", `stalled? ${formatStalledDuration(stalled)}`)}`);
7967
8066
  if (status.error) lines.push(` ${theme.fg("error", `${status.error.code}: ${status.error.message}`)}`);
7968
8067
  if (expanded) {
@@ -8028,7 +8127,7 @@ function subagentProgressBlock(status, args, theme, freezeAt) {
8028
8127
  render(width) {
8029
8128
  const now = TERMINAL_STATES.has(current.state) ? frozenAt : Date.now();
8030
8129
  if (!TERMINAL_STATES.has(current.state)) frozenAt = now;
8031
- const frame = SPINNER2[Math.floor(now / 80) % SPINNER2.length] ?? "\u25C7";
8130
+ const frame = SPINNER2[Math.floor(now / REPAINT_MS) % SPINNER2.length] ?? "\u25C7";
8032
8131
  return formatSubagentProgress(current, args, currentTheme, frame, now, expanded).split("\n").map((line) => truncateToWidth4(line, Math.max(1, width), "\u2026"));
8033
8132
  },
8034
8133
  invalidate() {
@@ -8046,14 +8145,14 @@ function renderSubagentResult(result, options, theme, context) {
8046
8145
  if (status?.state === "running" && options.isPartial && !state.subagentSpinner) {
8047
8146
  state.subagentSpinner = setInterval(() => {
8048
8147
  context.invalidate();
8049
- }, 80);
8148
+ }, REPAINT_MS);
8050
8149
  state.subagentSpinner.unref();
8051
8150
  } else if ((!options.isPartial || status?.state !== "running") && state.subagentSpinner) {
8052
8151
  clearInterval(state.subagentSpinner);
8053
8152
  delete state.subagentSpinner;
8054
8153
  }
8055
- if (!status || context.isError) return textBlock2(resultText(result));
8056
- if (!options.isPartial && status.state === "running") return textBlock2(formatSubagentLaunch(status, context.args, theme, options.expanded));
8154
+ if (!status || context.isError) return textBlock(resultText(result));
8155
+ if (!options.isPartial && status.state === "running") return textBlock(formatSubagentLaunch(status, context.args, theme, options.expanded));
8057
8156
  if (TERMINAL_STATES.has(status.state)) state.subagentProgressFrozenAt ??= Date.now();
8058
8157
  else delete state.subagentProgressFrozenAt;
8059
8158
  let component = state.subagentProgressComponent;
@@ -8175,7 +8274,7 @@ function createSubagentBackgroundWidget(host = {}) {
8175
8274
  showing = true;
8176
8275
  timer = setInterval(() => {
8177
8276
  requestRender?.();
8178
- }, 80);
8277
+ }, REPAINT_MS);
8179
8278
  timer.unref();
8180
8279
  } catch {
8181
8280
  hide();
@@ -8211,35 +8310,35 @@ function createSubagentBackgroundWidget(host = {}) {
8211
8310
  }
8212
8311
  function renderSubagentInspectCall(args, theme) {
8213
8312
  const title = theme.fg("toolTitle", theme.bold("subagents_inspect"));
8214
- return textBlock2(args.id ? `${title} ${theme.fg("accent", args.id)}` : `${title} ${theme.fg("muted", "all")}`);
8313
+ return textBlock(args.id ? `${title} ${theme.fg("accent", args.id)}` : `${title} ${theme.fg("muted", args.scope === "all" ? "all" : "session")}`);
8215
8314
  }
8216
8315
  function renderSubagentInspectResult(result, options, theme, args) {
8217
8316
  const status = statusValue2(result.details);
8218
- if (status) return textBlock2(formatSubagentInspection(status, args, result.details, theme, options.expanded));
8317
+ if (status) return textBlock(formatSubagentInspection(status, args, result.details, theme, options.expanded));
8219
8318
  if (Array.isArray(result.details)) {
8220
8319
  const statuses = result.details.map(statusValue2).filter((value) => value !== void 0);
8221
8320
  const lines = [theme.bold(theme.fg("accent", `Subagents (${String(statuses.length)})`)), ...statuses.map((entry) => {
8222
8321
  const color = stateColor(entry.state);
8223
8322
  return ` ${theme.fg(color, stateGlyph(entry.state, "\u25C7"))} ${entry.id.slice(0, 8)} ${theme.fg(color, `[${entry.state}]`)}`;
8224
8323
  })];
8225
- return textBlock2(lines.join("\n"));
8324
+ return textBlock(lines.join("\n"));
8226
8325
  }
8227
- return textBlock2(resultText(result));
8326
+ return textBlock(resultText(result));
8228
8327
  }
8229
8328
  function renderSubagentControlCall(name, args, theme) {
8230
8329
  const title = theme.fg("toolTitle", theme.bold(name));
8231
8330
  const message = args.message ? ` ${theme.fg("dim", args.message)}` : "";
8232
- return textBlock2(`${title} ${theme.fg("accent", args.id)}${message}`);
8331
+ return textBlock(`${title} ${theme.fg("accent", args.id)}${message}`);
8233
8332
  }
8234
8333
  function renderSubagentControlResult(result, theme) {
8235
8334
  const status = statusValue2(result.details);
8236
8335
  if (status) {
8237
8336
  const color = stateColor(status.state);
8238
- return textBlock2(`${theme.fg(color, stateGlyph(status.state, "\u25C7"))} ${status.id.slice(0, 8)} ${theme.fg(color, `[${status.state}]`)}`);
8337
+ return textBlock(`${theme.fg(color, stateGlyph(status.state, "\u25C7"))} ${status.id.slice(0, 8)} ${theme.fg(color, `[${status.state}]`)}`);
8239
8338
  }
8240
8339
  const record2 = typeof result.details === "object" && result.details !== null && !Array.isArray(result.details) ? result.details : void 0;
8241
- if (record2 && typeof record2.id === "string") return textBlock2(`${theme.fg("success", "\u2713")} ${record2.id.slice(0, 8)}`);
8242
- return textBlock2(resultText(result));
8340
+ if (record2 && typeof record2.id === "string") return textBlock(`${theme.fg("success", "\u2713")} ${record2.id.slice(0, 8)}`);
8341
+ return textBlock(resultText(result));
8243
8342
  }
8244
8343
 
8245
8344
  // subagents/src/index.ts
@@ -8268,7 +8367,7 @@ function serialize(value) {
8268
8367
  }
8269
8368
  }
8270
8369
  function toolResult(value) {
8271
- return { content: [{ type: "text", text: serialize(value) }], details: value };
8370
+ return { content: [{ type: "text", text: serialize(value) }], details: value, structuredContent: value };
8272
8371
  }
8273
8372
  function managerContext2(toolCallId, signal, onUpdate, context) {
8274
8373
  return {
@@ -8292,6 +8391,7 @@ function createSubagentTools(manager) {
8292
8391
  "Do not poll a running ID; use subagents_inspect({ id }) when you need its current status or terminal result."
8293
8392
  ],
8294
8393
  parameters: SUBAGENTS_RUN_PARAMETERS,
8394
+ outputSchema: SUBAGENT_STATUS_OUTPUT,
8295
8395
  async execute(toolCallId, params, signal, onUpdate, context) {
8296
8396
  return toolResult(await manager.run(validateSubagentRunRequest(params), managerContext2(toolCallId, signal, onUpdate, context)));
8297
8397
  },
@@ -8305,8 +8405,9 @@ function createSubagentTools(manager) {
8305
8405
  defineTool2({
8306
8406
  name: "subagents_inspect",
8307
8407
  label: "Subagents Inspect",
8308
- description: "Inspect durable subagent runs. Omit id for ordered run summaries, or provide id for detailed status, progress, activity, accounting, tool calls, timestamps, worktree metadata, and a terminal value or error when available.",
8408
+ description: "Inspect durable subagent runs. Omit id for ordered run summaries of the current session (scope all for every session), or provide id for detailed status, progress, activity, accounting, tool calls, timestamps, worktree metadata, and a terminal value or error when available.",
8309
8409
  parameters: SUBAGENTS_INSPECT_PARAMETERS,
8410
+ outputSchema: SUBAGENTS_INSPECT_OUTPUT,
8310
8411
  async execute(toolCallId, params, signal, onUpdate, context) {
8311
8412
  return toolResult(await manager.inspect(validateSubagentInspectRequest(params), managerContext2(toolCallId, signal, onUpdate, context)));
8312
8413
  },
@@ -8322,6 +8423,7 @@ function createSubagentTools(manager) {
8322
8423
  label: "Subagents Steer",
8323
8424
  description: "Send a message to a running subagent. The message is queued safely if its steering handler is not ready; settled runs cannot be steered.",
8324
8425
  parameters: SUBAGENTS_STEER_PARAMETERS,
8426
+ outputSchema: SUBAGENTS_STEER_OUTPUT,
8325
8427
  async execute(toolCallId, params, signal, onUpdate, context) {
8326
8428
  return toolResult(await manager.steer(validateSubagentSteerRequest(params), managerContext2(toolCallId, signal, onUpdate, context)));
8327
8429
  },
@@ -8337,6 +8439,7 @@ function createSubagentTools(manager) {
8337
8439
  label: "Subagents Stop",
8338
8440
  description: 'Stop one running subagent, abort its active session, persist state "stopped", and clean its worktree without affecting sibling runs.',
8339
8441
  parameters: SUBAGENTS_STOP_PARAMETERS,
8442
+ outputSchema: SUBAGENT_STATUS_OUTPUT,
8340
8443
  async execute(toolCallId, params, signal, onUpdate, context) {
8341
8444
  return toolResult(await manager.stop(validateSubagentIdRequest(params, "subagents_stop"), managerContext2(toolCallId, signal, onUpdate, context)));
8342
8445
  },
@@ -8352,6 +8455,7 @@ function createSubagentTools(manager) {
8352
8455
  label: "Subagents Retry",
8353
8456
  description: "Start a fresh run from a failed or stopped subagent's persisted request. The new run gets a new ID and preserves its original background or foreground mode.",
8354
8457
  parameters: SUBAGENTS_RETRY_PARAMETERS,
8458
+ outputSchema: SUBAGENT_STATUS_OUTPUT,
8355
8459
  async execute(toolCallId, params, signal, onUpdate, context) {
8356
8460
  return toolResult(await manager.retry(validateSubagentIdRequest(params, "subagents_retry"), managerContext2(toolCallId, signal, onUpdate, context)));
8357
8461
  },
@@ -8393,7 +8497,8 @@ function createSubagentsExtension(options = {}, activeTools, notify, onStatus, o
8393
8497
  }
8394
8498
  function registerSubagentsExtension(pi, options = {}) {
8395
8499
  const getActiveTools = pi.getActiveTools;
8396
- const activeTools = getActiveTools === void 0 ? void 0 : () => getActiveTools.call(pi);
8500
+ const getAllTools = pi.getAllTools;
8501
+ const activeTools = getActiveTools === void 0 ? void 0 : () => reachableTools({ getActiveTools: () => getActiveTools.call(pi), ...getAllTools === void 0 ? {} : { getAllTools: () => getAllTools.call(pi) } });
8397
8502
  const sendMessage = pi.sendMessage;
8398
8503
  const notify = sendMessage === void 0 ? void 0 : (notification) => {
8399
8504
  sendMessage.call(pi, { customType: "subagents", content: notificationContent(notification), display: true, details: notification }, { deliverAs: "steer", triggerTurn: true });
@@ -8410,7 +8515,8 @@ function registerSubagentsExtension(pi, options = {}) {
8410
8515
  const registry = loadingRegistry();
8411
8516
  if (typeof registry.observeSubagentStatus === "function") registry.observeSubagentStatus(status, request);
8412
8517
  }, onResourceWarning);
8413
- for (const tool of extension2.tools) pi.registerTool(tool);
8518
+ const codemodeTools = loadCodemodeToolsSetting(options.managerDependencies?.agentDir);
8519
+ for (const tool of extension2.tools) pi.registerTool({ ...tool, ...workflowToolExposure(tool.name, codemodeTools) });
8414
8520
  if (pi.registerCommand !== void 0) registerSubagentNavigator(pi.registerCommand.bind(pi), extension2.manager, storageDirectory2(options), options.clipboard);
8415
8521
  if (pi.on !== void 0) {
8416
8522
  setSubagentManager(extension2.manager);
@@ -8433,15 +8539,17 @@ function extension(pi, options = {}) {
8433
8539
  }
8434
8540
  export {
8435
8541
  SUBAGENTS_ID_PARAMETERS,
8542
+ SUBAGENTS_INSPECT_OUTPUT,
8436
8543
  SUBAGENTS_INSPECT_PARAMETERS,
8437
8544
  SUBAGENTS_RETRY_PARAMETERS,
8438
8545
  SUBAGENTS_RUN_PARAMETERS,
8546
+ SUBAGENTS_STEER_OUTPUT,
8439
8547
  SUBAGENTS_STEER_PARAMETERS,
8440
8548
  SUBAGENTS_STOP_PARAMETERS,
8441
8549
  SUBAGENTS_TOOL_NAMES,
8442
- SUBAGENTS_TOOL_SCHEMAS,
8443
8550
  SUBAGENT_ATTEMPT_DETAILS_LIMIT,
8444
8551
  SUBAGENT_MAX_RETRIES,
8552
+ SUBAGENT_STATUS_OUTPUT,
8445
8553
  SUBAGENT_SYSTEM_PROMPT_LIMIT,
8446
8554
  attemptValue,
8447
8555
  createRunStoreWorktreeAdapter,