@marcoscale98/pi-extensible-workflows 5.17.0-fork.1 → 6.2.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.
- package/CHANGELOG.md +145 -0
- package/README.md +2 -2
- package/dist/src/agent-execution.d.ts +43 -10
- package/dist/src/agent-execution.js +442 -162
- package/dist/src/background-widget.d.ts +5 -1
- package/dist/src/background-widget.js +5 -10
- package/dist/src/decoders.d.ts +2 -3
- package/dist/src/decoders.js +59 -37
- package/dist/src/execution.d.ts +6 -2
- package/dist/src/execution.js +48 -7
- package/dist/src/host-delivery.js +5 -8
- package/dist/src/host-navigator.js +5 -2
- package/dist/src/host-phases.d.ts +1 -0
- package/dist/src/host-recovery.d.ts +11 -8
- package/dist/src/host-recovery.js +14 -22
- package/dist/src/host-runtime.js +56 -5
- package/dist/src/host-view.d.ts +6 -1
- package/dist/src/host-view.js +46 -20
- package/dist/src/host.d.ts +2 -2
- package/dist/src/host.js +246 -118
- package/dist/src/index.d.ts +1 -2
- package/dist/src/index.js +1985 -1690
- package/dist/src/index.js.map +3 -3
- package/dist/src/paths.d.ts +8 -5
- package/dist/src/paths.js +24 -13
- package/dist/src/persistence.d.ts +1 -0
- package/dist/src/persistence.js +1 -0
- package/dist/src/pi-runtime-runner.js +4 -1
- package/dist/src/registry.d.ts +9 -7
- package/dist/src/registry.js +29 -71
- package/dist/src/runtime/agent-runner.d.ts +2 -0
- package/dist/src/script-tools.d.ts +27 -0
- package/dist/src/script-tools.js +87 -0
- package/dist/src/session-lease.d.ts +1 -1
- package/dist/src/session-lease.js +45 -11
- package/dist/src/settings.d.ts +19 -3
- package/dist/src/settings.js +63 -50
- package/dist/src/store.d.ts +3 -1
- package/dist/src/store.js +17 -1
- package/dist/src/trajectory.d.ts +12 -3
- package/dist/src/trajectory.js +32 -11
- package/dist/src/types.d.ts +129 -45
- package/dist/src/types.js +5 -8
- package/dist/src/utils.d.ts +21 -1
- package/dist/src/utils.js +46 -6
- package/dist/src/validation.d.ts +14 -3
- package/dist/src/validation.js +143 -87
- package/dist/starter/index.js +8 -11
- package/dist/starter/index.js.map +1 -1
- package/dist/starter/review-loop.d.ts +0 -13
- package/dist/starter/review-loop.js +8 -9
- package/dist/subagents/index.js +904 -956
- package/dist/subagents/index.js.map +3 -3
- package/dist/subagents/src/contracts.d.ts +48 -31
- package/dist/subagents/src/contracts.js +20 -9
- package/dist/subagents/src/index.d.ts +1 -1
- package/dist/subagents/src/index.js +14 -8
- package/dist/subagents/src/manager.js +52 -73
- package/dist/subagents/src/navigator.js +3 -14
- package/dist/subagents/src/view.d.ts +1 -1
- package/dist/subagents/src/view.js +15 -68
- package/dist/subagents/src/worktree.js +1 -1
- package/dist/trajectory/assets/index.html +35 -13
- package/dist/trajectory/index.js +576 -932
- package/dist/trajectory/index.js.map +3 -3
- package/dist/trajectory/src/assets/index.html +35 -13
- package/dist/trajectory/src/index.js +134 -104
- package/dist/trajectory/src/server.js +268 -27
- package/dist/trajectory/src/server.js.map +3 -3
- package/dist/trajectory/src/startup-mutex.d.ts +17 -0
- package/dist/trajectory/src/startup-mutex.js +172 -0
- package/examples/workflow-extension-template/README.md +4 -7
- package/examples/workflow-extension-template/extension.test.mjs +4 -8
- package/examples/workflow-extension-template/index.js +0 -3
- package/package.json +10 -10
- package/skills/pi-extensible-workflows/SKILL.md +12 -8
- package/src/agent-execution.ts +412 -164
- package/src/background-widget.ts +5 -11
- package/src/decoders.ts +51 -37
- package/src/execution.ts +46 -9
- package/src/host-delivery.ts +5 -8
- package/src/host-navigator.ts +4 -2
- package/src/host-phases.ts +1 -1
- package/src/host-recovery.ts +23 -28
- package/src/host-runtime.ts +44 -6
- package/src/host-view.ts +41 -16
- package/src/host.ts +229 -142
- package/src/index.ts +1 -2
- package/src/paths.ts +18 -9
- package/src/persistence.ts +1 -0
- package/src/pi-runtime-runner.ts +3 -1
- package/src/registry.ts +28 -64
- package/src/runtime/agent-runner.ts +2 -0
- package/src/script-tools.ts +76 -0
- package/src/session-lease.ts +34 -6
- package/src/settings.ts +56 -50
- package/src/store.ts +18 -2
- package/src/trajectory.ts +32 -15
- package/src/types.ts +82 -34
- package/src/utils.ts +42 -5
- package/src/validation.ts +121 -80
- package/starter/index.ts +0 -1
- package/starter/review-loop.ts +8 -9
- package/starter/roles/developer.md +0 -1
- package/starter/roles/oracle.md +0 -1
- package/starter/roles/researcher.md +0 -1
- package/starter/roles/reviewer.md +0 -1
- package/starter/roles/scout.md +0 -1
- package/subagents/README.md +10 -16
- package/subagents/src/contracts.ts +21 -11
- package/subagents/src/index.ts +17 -8
- package/subagents/src/manager.ts +48 -128
- package/subagents/src/navigator.ts +4 -13
- package/subagents/src/view.ts +16 -63
- package/subagents/src/worktree.ts +1 -1
- package/trajectory/src/assets/index.html +35 -13
- package/trajectory/src/index.ts +112 -91
- package/trajectory/src/server.ts +46 -10
- package/trajectory/src/startup-mutex.ts +127 -0
- package/dist/src/roles.d.ts +0 -70
- package/dist/src/roles.js +0 -325
- package/dist/starter/roles/developer.md +0 -6
- package/dist/starter/roles/oracle.md +0 -18
- package/dist/starter/roles/researcher.md +0 -20
- package/dist/starter/roles/reviewer.md +0 -19
- package/dist/starter/roles/scout.md +0 -18
- package/examples/workflow-extension-template/roles/reviewer.md +0 -4
- package/src/roles.ts +0 -326
package/dist/src/settings.js
CHANGED
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
import { atomicWriteFile } from "./persistence.js";
|
|
2
2
|
import { mkdirSync, readFileSync } from "node:fs";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
3
5
|
import { homedir } from "node:os";
|
|
4
|
-
import {
|
|
6
|
+
import { resolve } from "node:path";
|
|
5
7
|
import { fileURLToPath } from "node:url";
|
|
6
|
-
import { getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
7
|
-
import { isContextFileScope } from "./types.js";
|
|
8
|
-
import { annotateModelAliasError, deepFreeze, errorText, fail, isNodeError, jsonValue, modelCapability, object, positiveInteger, resourcePatternHasMagic, unknownModel, validateModelAliases, validateResourcePattern, validWorkflowExtensionNamespace } from "./utils.js";
|
|
9
8
|
import { canonicalPath, workflowProjectSettingsPath } from "./paths.js";
|
|
10
9
|
export { workflowProjectSettingsPath } from "./paths.js";
|
|
11
|
-
|
|
10
|
+
import { isContextFileScope } from "./types.js";
|
|
11
|
+
import { annotateModelAliasError, deepFreeze, errorText, fail, isNodeError, modelCapability, object, positiveInteger, unknownModel, validateModelAliases } from "./utils.js";
|
|
12
|
+
import { jsonValue, resourcePatternHasMagic, validateResourcePattern, validWorkflowExtensionNamespace } from "./utils.js";
|
|
13
|
+
const WORKFLOW_DIRECTORY = "pi-extensible-workflows";
|
|
12
14
|
export const DEFAULT_SETTINGS = Object.freeze({ concurrency: 8, backgroundWidget: true });
|
|
13
|
-
export function workflowSettingsPath(agentDir = getAgentDir()) { return join(agentDir,
|
|
15
|
+
export function workflowSettingsPath(agentDir = getAgentDir()) { return join(agentDir, WORKFLOW_DIRECTORY, "settings.json"); }
|
|
14
16
|
function normalizedResourcePath(value, settingsPath) {
|
|
15
|
-
|
|
17
|
+
// Built-in extensions are named `builtin:<name>`, not by a path.
|
|
18
|
+
if (value === "*" || value.startsWith("builtin:"))
|
|
16
19
|
return value;
|
|
17
20
|
let expanded = value === "~" ? homedir() : value.startsWith("~/") || value.startsWith("~\\") ? join(homedir(), value.slice(2)) : value;
|
|
18
21
|
if (expanded.startsWith("file://"))
|
|
@@ -81,23 +84,25 @@ function selectorsFromSettings(settings) {
|
|
|
81
84
|
};
|
|
82
85
|
}
|
|
83
86
|
function selectorSet(value) { return { skills: [...(value?.skills ?? [])], extensions: [...(value?.extensions ?? [])], ...(value?.tools === undefined ? {} : { tools: [...value.tools] }) }; }
|
|
84
|
-
export function validateContextFileScopes(value,
|
|
87
|
+
export function validateContextFileScopes(value, sourcePath) {
|
|
85
88
|
if (value === undefined)
|
|
86
89
|
return undefined;
|
|
87
90
|
if (!Array.isArray(value) || !value.every(isContextFileScope))
|
|
88
|
-
fail("INVALID_METADATA", `${
|
|
91
|
+
fail("INVALID_METADATA", `${sourcePath}.contextFiles must be an array containing only global, project, or cwd`);
|
|
89
92
|
return [...value];
|
|
90
93
|
}
|
|
91
94
|
export function validateWorkflowExtensionSettings(value, settingsPath, errorCode = "INVALID_SETTINGS") {
|
|
92
95
|
if (value === undefined)
|
|
93
96
|
return undefined;
|
|
97
|
+
if (!object(value) || !jsonValue(value))
|
|
98
|
+
fail(errorCode, `${settingsPath}.extensionSettings must be a JSON object`);
|
|
99
|
+
for (const namespace of Object.keys(value))
|
|
100
|
+
if (!validWorkflowExtensionNamespace(namespace))
|
|
101
|
+
fail(errorCode, `${settingsPath}.extensionSettings contains an invalid namespace: ${namespace}`);
|
|
102
|
+
const generic = value;
|
|
94
103
|
const base = `${settingsPath}.extensionSettings`;
|
|
95
|
-
if (!object(value))
|
|
96
|
-
fail(errorCode, `${base} must be an object`);
|
|
97
104
|
const normalized = {};
|
|
98
|
-
for (const [namespace, raw] of Object.entries(
|
|
99
|
-
if (!validWorkflowExtensionNamespace(namespace))
|
|
100
|
-
fail(errorCode, `${base} contains an invalid namespace: ${namespace}`);
|
|
105
|
+
for (const [namespace, raw] of Object.entries(generic)) {
|
|
101
106
|
if (namespace === "herdr") {
|
|
102
107
|
if (!object(raw))
|
|
103
108
|
fail(errorCode, `${base}.herdr must be an object`);
|
|
@@ -118,8 +123,6 @@ export function validateWorkflowExtensionSettings(value, settingsPath, errorCode
|
|
|
118
123
|
normalized.trajectory = Object.freeze({ ...(raw.port === undefined ? {} : { port: raw.port }) });
|
|
119
124
|
continue;
|
|
120
125
|
}
|
|
121
|
-
if (!jsonValue(raw))
|
|
122
|
-
fail(errorCode, `${base}.${namespace} must be JSON-compatible`);
|
|
123
126
|
normalized[namespace] = structuredClone(raw);
|
|
124
127
|
}
|
|
125
128
|
return deepFreeze(normalized);
|
|
@@ -152,7 +155,7 @@ function parseSettings(path, partial) {
|
|
|
152
155
|
}
|
|
153
156
|
if (!object(parsed))
|
|
154
157
|
fail("INVALID_SETTINGS", `Workflow settings at ${path} must be an object`);
|
|
155
|
-
const allowed = new Set(["concurrency", "modelAliases", "skills", "extensions", "extensionSettings", "tools", "retention", "worktreePostCreateCommand", ...(partial ? [] : ["backgroundWidget"])]);
|
|
158
|
+
const allowed = new Set(["concurrency", "modelAliases", "skills", "extensions", "extensionSettings", "tools", "retention", "worktreePostCreateCommand", ...(partial ? [] : ["backgroundWidget", "codemodeTools"])]);
|
|
156
159
|
const unknown = Object.keys(parsed).find((key) => !allowed.has(key));
|
|
157
160
|
if (Object.prototype.hasOwnProperty.call(parsed, "disabledAgentResources"))
|
|
158
161
|
fail("INVALID_SETTINGS", `disabledAgentResources is no longer supported; use skills, extensions, and tools selectors (settings: ${path})`);
|
|
@@ -164,6 +167,9 @@ function parseSettings(path, partial) {
|
|
|
164
167
|
const backgroundWidget = parsed.backgroundWidget === undefined ? (partial ? undefined : DEFAULT_SETTINGS.backgroundWidget) : parsed.backgroundWidget;
|
|
165
168
|
if (backgroundWidget !== undefined && typeof backgroundWidget !== "boolean")
|
|
166
169
|
fail("INVALID_SETTINGS", `${path}.backgroundWidget must be a boolean`);
|
|
170
|
+
const codemodeTools = parsed.codemodeTools;
|
|
171
|
+
if (codemodeTools !== undefined && codemodeTools !== "all" && codemodeTools !== "read-only" && codemodeTools !== "none")
|
|
172
|
+
fail("INVALID_SETTINGS", `${path}.codemodeTools must be "all", "read-only", or "none"`);
|
|
167
173
|
const modelAliases = parsed.modelAliases === undefined ? undefined : validateModelAliases(parsed.modelAliases, path);
|
|
168
174
|
const skills = validateSelectorList(parsed.skills, path, "skills");
|
|
169
175
|
const tools = validateSelectorList(parsed.tools, path, "tools");
|
|
@@ -172,49 +178,52 @@ function parseSettings(path, partial) {
|
|
|
172
178
|
const retention = validateRetention(parsed.retention, path);
|
|
173
179
|
const worktreePostCreateCommand = validateWorktreePostCreateCommand(parsed.worktreePostCreateCommand, path);
|
|
174
180
|
return Object.freeze({
|
|
175
|
-
...(concurrency === undefined ? {} : { concurrency }), ...(backgroundWidget === undefined ? {} : { backgroundWidget }), ...(modelAliases === undefined ? {} : { modelAliases }),
|
|
181
|
+
...(concurrency === undefined ? {} : { concurrency }), ...(backgroundWidget === undefined ? {} : { backgroundWidget }), ...(codemodeTools === undefined ? {} : { codemodeTools }), ...(modelAliases === undefined ? {} : { modelAliases }),
|
|
176
182
|
...(skills === undefined ? {} : { skills }), ...(extensions === undefined ? {} : { extensions }),
|
|
177
183
|
...(extensionSettings === undefined ? {} : { extensionSettings }), ...(tools === undefined ? {} : { tools }), ...(retention === undefined ? {} : { retention }),
|
|
178
184
|
...(worktreePostCreateCommand === undefined ? {} : { worktreePostCreateCommand }),
|
|
179
185
|
});
|
|
180
186
|
}
|
|
181
187
|
export function loadSettings(path = workflowSettingsPath()) { return parseSettings(path, false); }
|
|
188
|
+
const READ_ONLY_WORKFLOW_TOOLS = new Set(["workflow_status", "workflow_catalog", "subagents_inspect"]);
|
|
189
|
+
/**
|
|
190
|
+
* Exposure and annotations of a workflow or subagent tool. Under the global `codemodeTools` setting,
|
|
191
|
+
* `model-only` keeps the model's direct access and stops codemode scripts from calling the tool.
|
|
192
|
+
* Tools are registered once at load, so the setting is global and applies after a reload.
|
|
193
|
+
* Read-only tools carry `readOnlyHint` so permission extensions need not confirm them.
|
|
194
|
+
*/
|
|
195
|
+
export function workflowToolExposure(name, codemodeTools) {
|
|
196
|
+
const readOnly = READ_ONLY_WORKFLOW_TOOLS.has(name);
|
|
197
|
+
return { ...(codemodeTools === "none" || (codemodeTools === "read-only" && !readOnly) ? { exposure: "model-only" } : {}), ...(readOnly ? { annotations: { readOnlyHint: true } } : {}) };
|
|
198
|
+
}
|
|
199
|
+
/** The `codemodeTools` setting at load time. Invalid settings keep the default; launches report them. */
|
|
200
|
+
export function loadCodemodeToolsSetting(agentDir) {
|
|
201
|
+
try {
|
|
202
|
+
return loadSettings(workflowSettingsPath(agentDir)).codemodeTools;
|
|
203
|
+
}
|
|
204
|
+
catch {
|
|
205
|
+
return undefined;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
182
208
|
export function loadSettingsOverrides(path) { return parseSettings(path, true); }
|
|
183
209
|
export function resolveWorkflowSettings(cwd, projectTrusted, globalSettingsPath = workflowSettingsPath()) {
|
|
184
210
|
const projectSettingsPath = workflowProjectSettingsPath(cwd);
|
|
185
|
-
const
|
|
186
|
-
const
|
|
187
|
-
const
|
|
188
|
-
const
|
|
189
|
-
const
|
|
190
|
-
const projectSelectors = selectorsFromSettings(project);
|
|
191
|
-
const effectiveSelectors = selectorSet({
|
|
192
|
-
skills: [...(globalSelectors.skills ?? []), ...(projectSelectors.skills ?? [])],
|
|
193
|
-
extensions: [...(globalSelectors.extensions ?? []), ...(projectSelectors.extensions ?? [])],
|
|
194
|
-
...(globalSelectors.tools === undefined && projectSelectors.tools === undefined ? {} : { tools: [...(globalSelectors.tools ?? []), ...(projectSelectors.tools ?? [])] }),
|
|
195
|
-
});
|
|
196
|
-
const hasExtensionSelectors = global.extensions !== undefined || project.extensions !== undefined;
|
|
197
|
-
const extensionSettings = projectHas("extensionSettings") ? project.extensionSettings : global.extensionSettings;
|
|
198
|
-
const sources = {
|
|
199
|
-
concurrency: projectHas("concurrency") ? projectSettingsPath : globalSettingsPath,
|
|
200
|
-
modelAliases: projectHas("modelAliases") ? projectSettingsPath : globalSettingsPath,
|
|
201
|
-
skills: sourceFor("skills"), extensions: sourceFor("extensions"), tools: sourceFor("tools"),
|
|
202
|
-
...(extensionSettings === undefined ? {} : { extensionSettings: projectHas("extensionSettings") ? projectSettingsPath : globalSettingsPath }),
|
|
203
|
-
...(project.retention === undefined && global.retention === undefined ? {} : { retention: project.retention === undefined ? globalSettingsPath : projectSettingsPath }),
|
|
204
|
-
...(projectHas("worktreePostCreateCommand") || global.worktreePostCreateCommand !== undefined ? { worktreePostCreateCommand: projectHas("worktreePostCreateCommand") ? projectSettingsPath : globalSettingsPath } : {}),
|
|
205
|
-
};
|
|
211
|
+
const consumerGlobal = loadSettings(globalSettingsPath);
|
|
212
|
+
const consumerProject = projectTrusted ? loadSettingsOverrides(projectSettingsPath) : Object.freeze({});
|
|
213
|
+
const global = consumerGlobal;
|
|
214
|
+
const project = consumerProject;
|
|
215
|
+
const selectorSources = { global: selectorsFromSettings(global), project: selectorsFromSettings(project) };
|
|
206
216
|
const effective = Object.freeze({
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
...(
|
|
210
|
-
...(
|
|
211
|
-
...(hasExtensionSelectors ? { extensions: effectiveSelectors.extensions } : {}),
|
|
212
|
-
...(extensionSettings === undefined ? {} : { extensionSettings }),
|
|
213
|
-
...(effectiveSelectors.tools?.length ? { tools: effectiveSelectors.tools } : global.tools !== undefined || project.tools !== undefined ? { tools: effectiveSelectors.tools } : {}),
|
|
214
|
-
...((project.retention ?? global.retention) === undefined ? {} : { retention: project.retention ?? global.retention }),
|
|
215
|
-
...(projectHas("worktreePostCreateCommand") ? { worktreePostCreateCommand: project.worktreePostCreateCommand } : global.worktreePostCreateCommand === undefined ? {} : { worktreePostCreateCommand: global.worktreePostCreateCommand }),
|
|
217
|
+
...global, ...project,
|
|
218
|
+
skills: [...(global.skills ?? []), ...(project.skills ?? [])],
|
|
219
|
+
extensions: [...(global.extensions ?? []), ...(project.extensions ?? [])],
|
|
220
|
+
...(global.tools === undefined && project.tools === undefined ? {} : { tools: [...(global.tools ?? []), ...(project.tools ?? [])] }),
|
|
216
221
|
});
|
|
217
|
-
|
|
222
|
+
const sources = { concurrency: project.concurrency === undefined ? globalSettingsPath : projectSettingsPath, modelAliases: project.modelAliases === undefined ? globalSettingsPath : projectSettingsPath };
|
|
223
|
+
for (const key of ["skills", "extensions", "tools", "extensionSettings", "retention", "worktreePostCreateCommand"])
|
|
224
|
+
if (effective[key] !== undefined)
|
|
225
|
+
sources[key] = project[key] === undefined ? globalSettingsPath : projectSettingsPath;
|
|
226
|
+
return { globalSettingsPath, projectSettingsPath, projectTrusted, global, project, effective, sources, selectorSources };
|
|
218
227
|
}
|
|
219
228
|
export function validateModelAliasAvailability(aliases, names, availableModels, knownModels, settingsPath) {
|
|
220
229
|
for (const name of names) {
|
|
@@ -233,7 +242,7 @@ export function resolveAgentResourcePolicy(cwd, projectTrusted, globalSettingsPa
|
|
|
233
242
|
const global = selectorSet(selectorsFromSettings(resolved.global));
|
|
234
243
|
const project = selectorSet(selectorsFromSettings(resolved.project));
|
|
235
244
|
const effective = selectorSet(selectorsFromSettings(resolved.effective));
|
|
236
|
-
return { globalSettingsPath: resolved.globalSettingsPath, projectSettingsPath: resolved.projectSettingsPath, projectTrusted, global, project, effective, unmatchedSkills: [], unmatchedExtensions: [], unmatchedTools: [], selectorSources:
|
|
245
|
+
return { globalSettingsPath: resolved.globalSettingsPath, projectSettingsPath: resolved.projectSettingsPath, projectTrusted, global, project, effective, unmatchedSkills: [], unmatchedExtensions: [], unmatchedTools: [], selectorSources: resolved.selectorSources };
|
|
237
246
|
}
|
|
238
247
|
export function saveModelAliases(path = workflowSettingsPath(), aliases = {}) {
|
|
239
248
|
const normalized = validateModelAliases(aliases, path);
|
|
@@ -251,3 +260,7 @@ export function saveModelAliases(path = workflowSettingsPath(), aliases = {}) {
|
|
|
251
260
|
mkdirSync(dirname(path), { recursive: true });
|
|
252
261
|
atomicWriteFile(path, `${JSON.stringify({ ...parsed, modelAliases: normalized }, null, 2)}\n`, true);
|
|
253
262
|
}
|
|
263
|
+
export function canonicalExtensionSelector(selector, cwd) {
|
|
264
|
+
const negated = selector.startsWith("!");
|
|
265
|
+
return `${negated ? "!" : ""}${normalizedResourcePath(negated ? selector.slice(1) : selector, join(cwd, "settings.json"))}`;
|
|
266
|
+
}
|
package/dist/src/store.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type JsonValue, type LaunchSnapshot, type WorkflowRunEvent } from "./types.js";
|
|
1
|
+
import { type PreparedAgentConfiguration, type JsonValue, type LaunchSnapshot, type WorkflowLaunchMode, type WorkflowRunEvent } from "./types.js";
|
|
2
2
|
import { type AwaitingCheckpoint, type BorrowedWorktreeBinding, type CompletedOperation, type EffectiveSystemPrompt, type PendingWorkflowDecision, type PersistedOwnershipNode, type PersistedRun, type RunSummary, type WorktreeReference } from "./decoders.js";
|
|
3
3
|
export declare class RunStore {
|
|
4
4
|
#private;
|
|
@@ -28,6 +28,8 @@ export declare class RunStore {
|
|
|
28
28
|
loadSummary(): Promise<RunSummary>;
|
|
29
29
|
saveState(run: PersistedRun): Promise<void>;
|
|
30
30
|
updateState(update: (run: PersistedRun) => PersistedRun | Promise<PersistedRun>): Promise<PersistedRun>;
|
|
31
|
+
saveAgentConfiguration(key: string, configuration: PreparedAgentConfiguration): Promise<void>;
|
|
32
|
+
setLaunchMode(launchMode: WorkflowLaunchMode): Promise<void>;
|
|
31
33
|
saveSnapshot(snapshot: Readonly<LaunchSnapshot>): Promise<void>;
|
|
32
34
|
appendEvent(event: WorkflowRunEvent): Promise<void>;
|
|
33
35
|
saveOwnership(nodes: readonly PersistedOwnershipNode[]): Promise<void>;
|
package/dist/src/store.js
CHANGED
|
@@ -24,7 +24,7 @@ function summaryFromRun(run, directory, journal, previous, fallbackCreatedAt, no
|
|
|
24
24
|
const failedAt = run.failedAt ?? run.error?.failedAt;
|
|
25
25
|
const replayablePaths = [...new Set([...(run.retry?.completedPaths ?? []), ...Object.keys(journal.completed)])];
|
|
26
26
|
const incompletePaths = [...new Set([...(run.retry?.incompletePaths ?? []), ...(failedAt ? [failedAt] : [])])];
|
|
27
|
-
return { schemaVersion: 1, runId: run.id, sessionId: run.sessionId, workflowName: run.workflowName, state: run.state, createdAt, updatedAt: now, ...(previous?.terminalAt || HARD_TERMINAL_RUN_STATES.has(run.state) ? { terminalAt: previous?.terminalAt ?? now } : {}), usage: budgetUsage(run.usage), agents: run.agents.map(({ id, name, label, state,
|
|
27
|
+
return { schemaVersion: 1, runId: run.id, sessionId: run.sessionId, workflowName: run.workflowName, state: run.state, createdAt, updatedAt: now, ...(previous?.terminalAt || HARD_TERMINAL_RUN_STATES.has(run.state) ? { terminalAt: previous?.terminalAt ?? now } : {}), usage: budgetUsage(run.usage), agents: run.agents.map(({ id, name, label, state, attempts }) => ({ id, name, ...(label ? { label } : {}), state, attempts })), ...(run.error ? { error: run.error } : {}), ...(failedAt ? { failedAt } : {}), replayablePaths, incompletePaths, artifacts: summaryArtifacts(directory) };
|
|
28
28
|
}
|
|
29
29
|
function systemPromptStoragePath(directory) { return join(directory, SYSTEM_PROMPT_STORAGE); }
|
|
30
30
|
function systemPromptRecordsPath(directory) { return join(systemPromptStoragePath(directory), SYSTEM_PROMPT_RECORDS); }
|
|
@@ -171,6 +171,22 @@ export class RunStore {
|
|
|
171
171
|
});
|
|
172
172
|
return write;
|
|
173
173
|
}
|
|
174
|
+
async saveAgentConfiguration(key, configuration) {
|
|
175
|
+
await this.launchSnapshotLane.run(async () => {
|
|
176
|
+
const snapshot = decodeLaunchSnapshot(await json(join(this.directory, "snapshot.json")));
|
|
177
|
+
if (!snapshot)
|
|
178
|
+
throw new WorkflowError("RESUME_INCOMPATIBLE", "Workflow launch snapshot identity version is incompatible");
|
|
179
|
+
await atomicJson(join(this.directory, "snapshot.json"), { ...snapshot, agentConfigurations: { ...snapshot.agentConfigurations, [key]: configuration } });
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
async setLaunchMode(launchMode) {
|
|
183
|
+
await this.launchSnapshotLane.run(async () => {
|
|
184
|
+
const snapshot = decodeLaunchSnapshot(await json(join(this.directory, "snapshot.json")));
|
|
185
|
+
if (!snapshot)
|
|
186
|
+
throw new WorkflowError("RESUME_INCOMPATIBLE", "Workflow launch snapshot identity version is incompatible");
|
|
187
|
+
await atomicJson(join(this.directory, "snapshot.json"), { ...snapshot, launchMode });
|
|
188
|
+
});
|
|
189
|
+
}
|
|
174
190
|
async saveSnapshot(snapshot) {
|
|
175
191
|
const write = this.launchSnapshotLane.run(() => atomicJson(join(this.directory, "snapshot.json"), snapshot));
|
|
176
192
|
await write;
|
package/dist/src/trajectory.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type AwaitingCheckpoint, type CompletedOperation, type EffectiveSystemPrompt, type PersistedRun } from "./persistence.js";
|
|
2
|
-
import type { AgentAttemptSummary, AgentRecord, JsonValue, LaunchSnapshot, WorkflowAgentSessionReference } from "./types.js";
|
|
2
|
+
import type { AgentAttemptSummary, AgentRecord, JsonValue, LaunchSnapshot, WorkflowAgentSessionReference, WorkflowErrorCode, WorkflowScriptCall } from "./types.js";
|
|
3
3
|
import { type SubagentProgress, type SubagentRunRequest, type SubagentStatus } from "../subagents/src/contracts.js";
|
|
4
4
|
import type { TrajectoryAction, TrajectoryTarget } from "./trajectory-contracts.js";
|
|
5
5
|
export declare const TRAJECTORY_MAX_TRANSCRIPT_BYTES: number;
|
|
@@ -24,8 +24,17 @@ export type TrajectoryAgentOutput = {
|
|
|
24
24
|
export type TrajectoryAgent = AgentRecord & {
|
|
25
25
|
readonly output: TrajectoryAgentOutput;
|
|
26
26
|
};
|
|
27
|
-
export type
|
|
27
|
+
export type TrajectoryScriptCall = WorkflowScriptCall & {
|
|
28
|
+
readonly output: TrajectoryAgentOutput | {
|
|
29
|
+
readonly status: "completed";
|
|
30
|
+
} | {
|
|
31
|
+
readonly status: "failed" | "cancelled";
|
|
32
|
+
readonly code: WorkflowErrorCode;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
export type TrajectoryRunRecord = Omit<PersistedRun, "agents" | "scriptCalls"> & {
|
|
28
36
|
readonly agents: readonly TrajectoryAgent[];
|
|
37
|
+
readonly scriptCalls?: readonly TrajectoryScriptCall[];
|
|
29
38
|
};
|
|
30
39
|
export type TrajectoryRun = {
|
|
31
40
|
run: TrajectoryRunRecord;
|
|
@@ -54,7 +63,6 @@ export type TrajectorySubagent = {
|
|
|
54
63
|
sessionId: string;
|
|
55
64
|
cwd: string;
|
|
56
65
|
label?: string;
|
|
57
|
-
role?: string;
|
|
58
66
|
mode: "background" | "foreground";
|
|
59
67
|
state: SubagentStatus["state"];
|
|
60
68
|
startedAt?: number;
|
|
@@ -135,6 +143,7 @@ export type TrajectoryPublisherInput = {
|
|
|
135
143
|
loadTranscript?: TrajectoryTranscriptLoader;
|
|
136
144
|
handleAction: TrajectoryActionHandler;
|
|
137
145
|
};
|
|
146
|
+
export declare function isTimingTranscriptEntry(value: unknown): boolean;
|
|
138
147
|
export declare function applySystemPrompts(run: PersistedRun, prompts: readonly EffectiveSystemPrompt[]): PersistedRun;
|
|
139
148
|
export declare function applyToolDescriptions(run: PersistedRun, catalog: ReadonlyMap<string, string>): PersistedRun;
|
|
140
149
|
export declare function withPiToolDescriptions(run: PersistedRun): PersistedRun;
|
package/dist/src/trajectory.js
CHANGED
|
@@ -9,6 +9,7 @@ import { normalizeSubagentRunRequest } from "../subagents/src/contracts.js";
|
|
|
9
9
|
import { statusValue, subagentErrorValue } from "../subagents/src/decode.js";
|
|
10
10
|
import { isNodeError, jsonValue, object, resourcePatternHasMagic, selectResourcesByLayers } from "./utils.js";
|
|
11
11
|
import { canonicalPath, sameFilesystemPath } from "./paths.js";
|
|
12
|
+
import { TOOL_TIMING_ENTRY_TYPE } from "./tool-timing.js";
|
|
12
13
|
export const TRAJECTORY_MAX_TRANSCRIPT_BYTES = 2 * 1024 * 1024;
|
|
13
14
|
const TRAJECTORY_MAX_NON_TIMING_ENTRIES = 400;
|
|
14
15
|
function subagentOutput(options) {
|
|
@@ -50,7 +51,7 @@ function transcriptToolCallId(value) {
|
|
|
50
51
|
return part.id;
|
|
51
52
|
return undefined;
|
|
52
53
|
}
|
|
53
|
-
function isTimingTranscriptEntry(value) { return object(value) && value.type === "custom" && value.customType ===
|
|
54
|
+
export function isTimingTranscriptEntry(value) { return object(value) && value.type === "custom" && value.customType === TOOL_TIMING_ENTRY_TYPE; }
|
|
54
55
|
function timingToolCallId(value) {
|
|
55
56
|
if (!object(value) || !isTimingTranscriptEntry(value) || !object(value.data))
|
|
56
57
|
return undefined;
|
|
@@ -194,7 +195,8 @@ export function withPiToolDescriptionsForTools(tools, cwd) {
|
|
|
194
195
|
function canonicalExtensionSelector(selector, base) {
|
|
195
196
|
const negated = selector.startsWith("!");
|
|
196
197
|
const body = negated ? selector.slice(1) : selector;
|
|
197
|
-
|
|
198
|
+
// Built-in extensions are named `builtin:<name>`, not by a path.
|
|
199
|
+
if (body === "*" || body === "**" || body.startsWith("**/") || body.startsWith("builtin:"))
|
|
198
200
|
return selector;
|
|
199
201
|
const resolved = resolve(base, body);
|
|
200
202
|
if (resourcePatternHasMagic(body))
|
|
@@ -236,8 +238,8 @@ async function resolveResourceInspection(inspection, cwd, selectorCwd = cwd) {
|
|
|
236
238
|
return inspection;
|
|
237
239
|
}
|
|
238
240
|
const sources = inspection.selectorSources ?? { global: inspection.selectors, project: {} };
|
|
239
|
-
const skills = inspection.skills.length ? inspection.skills : selectResourcesByLayers([sources.global.skills, sources.project.skills, sources.
|
|
240
|
-
const extensions = inspection.extensions.length ? inspection.extensions : selectResourcesByLayers([sources.global.extensions, sources.project.extensions, sources.
|
|
241
|
+
const skills = inspection.skills.length ? inspection.skills : selectResourcesByLayers([sources.global.skills, sources.project.skills, sources.call?.skills], discovered.skills);
|
|
242
|
+
const extensions = inspection.extensions.length ? inspection.extensions : selectResourcesByLayers([sources.global.extensions, sources.project.extensions, sources.call?.extensions].map((layer) => layer?.map((selector) => canonicalExtensionSelector(selector, selectorCwd))), discovered.extensions);
|
|
241
243
|
return skills === inspection.skills && extensions === inspection.extensions ? inspection : { ...inspection, skills, extensions };
|
|
242
244
|
}
|
|
243
245
|
export async function withResolvedAttemptResources(attempt, cwd) {
|
|
@@ -280,11 +282,20 @@ function failedAgentOutput(agent) {
|
|
|
280
282
|
const status = agent.state === "cancelled" ? "cancelled" : "failed";
|
|
281
283
|
return { status, code: error?.code ?? (status === "cancelled" ? "CANCELLED" : "AGENT_FAILED"), message: error?.message ?? `Agent ${agent.state}` };
|
|
282
284
|
}
|
|
285
|
+
function operationOutput(operation) {
|
|
286
|
+
const bytes = serializedJsonBytes(operation.value);
|
|
287
|
+
return bytes > DEFAULT_MAX_BYTES ? { status: "truncated", kind: "result", bytes } : { status: "available", value: operation.value, bytes };
|
|
288
|
+
}
|
|
289
|
+
function outputForCall(call, operation) {
|
|
290
|
+
if (operation !== undefined)
|
|
291
|
+
return call.kind === "tool" ? { status: "completed" } : operationOutput(operation);
|
|
292
|
+
if (call.error)
|
|
293
|
+
return { status: call.error.code === "CANCELLED" ? "cancelled" : "failed", code: call.error.code, ...(call.kind === "shell" ? { message: call.error.message ?? "Shell failed" } : {}) };
|
|
294
|
+
return call.finishedAt === undefined ? { status: "pending" } : { status: "unavailable" };
|
|
295
|
+
}
|
|
283
296
|
function outputForAgent(agent, operation) {
|
|
284
|
-
if (operation !== undefined)
|
|
285
|
-
|
|
286
|
-
return bytes > DEFAULT_MAX_BYTES ? { status: "truncated", kind: "result", bytes } : { status: "available", value: operation.value, bytes };
|
|
287
|
-
}
|
|
297
|
+
if (operation !== undefined)
|
|
298
|
+
return operationOutput(operation);
|
|
288
299
|
if (agent.state === "failed" || agent.state === "cancelled")
|
|
289
300
|
return failedAgentOutput(agent);
|
|
290
301
|
if (agent.state === "completed")
|
|
@@ -294,7 +305,18 @@ function outputForAgent(agent, operation) {
|
|
|
294
305
|
export function applyTrajectoryAgentOutputs(run, operations) {
|
|
295
306
|
const byPath = new Map(operations.map((operation) => [operation.path, operation]));
|
|
296
307
|
const agents = run.agents.map((agent) => ({ ...agent, output: outputForAgent(agent, agent.resultPath === undefined ? undefined : byPath.get(agent.resultPath)) }));
|
|
297
|
-
|
|
308
|
+
const scriptCalls = run.scriptCalls?.map((call) => {
|
|
309
|
+
const recorded = { ...call, output: outputForCall(call, byPath.get(call.path)) };
|
|
310
|
+
if (call.kind === "tool") {
|
|
311
|
+
delete recorded.input;
|
|
312
|
+
delete recorded.inputBytes;
|
|
313
|
+
if (call.error)
|
|
314
|
+
recorded.error = { code: call.error.code };
|
|
315
|
+
}
|
|
316
|
+
return recorded;
|
|
317
|
+
});
|
|
318
|
+
const rest = run;
|
|
319
|
+
return { ...rest, agents, ...(scriptCalls === undefined ? {} : { scriptCalls }) };
|
|
298
320
|
}
|
|
299
321
|
function overlayTrajectoryRun(run, overlay) {
|
|
300
322
|
const overlaid = overlay(run);
|
|
@@ -304,7 +326,7 @@ function overlayTrajectoryRun(run, overlay) {
|
|
|
304
326
|
const output = previous?.status === "available" || previous?.status === "truncated" ? previous : outputForAgent(agent, undefined);
|
|
305
327
|
return { ...agent, output };
|
|
306
328
|
});
|
|
307
|
-
return { ...overlaid, agents };
|
|
329
|
+
return { ...overlaid, agents, ...(run.scriptCalls === undefined ? {} : { scriptCalls: run.scriptCalls }) };
|
|
308
330
|
}
|
|
309
331
|
async function loadTrajectoryRun(store, includeTranscripts = true) {
|
|
310
332
|
const value = await store.load();
|
|
@@ -555,7 +577,6 @@ async function loadTrajectorySubagent(directory, cwd, sessionId, includeTranscri
|
|
|
555
577
|
return {
|
|
556
578
|
id, sessionId, cwd, mode: request.mode ?? "background", state: status.state, request, tools, transcript,
|
|
557
579
|
...(request.label === undefined ? {} : { label: request.label }),
|
|
558
|
-
...(request.role === undefined ? {} : { role: request.role }),
|
|
559
580
|
...(status.startedAt === undefined ? {} : { startedAt: status.startedAt }),
|
|
560
581
|
...(status.finishedAt === undefined ? {} : { finishedAt: status.finishedAt }),
|
|
561
582
|
...(status.attempts === undefined ? {} : { attempts: status.attempts }),
|