@marcoscale98/pi-extensible-workflows 5.14.1-fork.1 → 5.17.0-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 +67 -0
- package/dist/src/agent-execution.js +36 -51
- package/dist/src/background-widget.d.ts +56 -0
- package/dist/src/background-widget.js +22 -15
- package/dist/src/decoders.js +2 -1
- package/dist/src/host-navigator.d.ts +18 -0
- package/dist/src/host-navigator.js +71 -13
- package/dist/src/host-view.d.ts +16 -1
- package/dist/src/host-view.js +109 -42
- package/dist/src/host.js +57 -24
- package/dist/src/index.d.ts +3 -1
- package/dist/src/index.js +867 -545
- package/dist/src/index.js.map +3 -3
- package/dist/src/registry.js +2 -1
- package/dist/src/roles.d.ts +70 -0
- package/dist/src/roles.js +325 -0
- package/dist/src/settings.d.ts +13 -0
- package/dist/src/settings.js +253 -0
- package/dist/src/trajectory.d.ts +29 -4
- package/dist/src/trajectory.js +58 -3
- package/dist/src/types.d.ts +0 -1
- package/dist/src/utils.d.ts +2 -1
- package/dist/src/utils.js +10 -0
- package/dist/src/validation.d.ts +5 -17
- package/dist/src/validation.js +9 -458
- package/dist/subagents/index.js +1132 -694
- package/dist/subagents/index.js.map +3 -3
- package/dist/subagents/src/contracts.d.ts +4 -0
- package/dist/subagents/src/index.d.ts +1 -1
- package/dist/subagents/src/index.js +2 -1
- package/dist/subagents/src/manager.js +29 -10
- package/dist/subagents/src/navigator.js +396 -247
- package/dist/subagents/src/view.d.ts +23 -2
- package/dist/subagents/src/view.js +96 -30
- package/dist/trajectory/assets/index.html +347 -231
- package/dist/trajectory/assets/prism.min.js +13 -0
- package/dist/trajectory/index.js +377 -257
- package/dist/trajectory/index.js.map +3 -3
- package/dist/trajectory/src/assets/index.html +347 -231
- package/dist/trajectory/src/assets/prism.min.js +13 -0
- package/dist/trajectory/src/export.js +4 -2
- package/dist/trajectory/src/index.d.ts +2 -0
- package/dist/trajectory/src/index.js +143 -42
- package/dist/trajectory/src/server.js +134 -9
- package/dist/trajectory/src/server.js.map +1 -1
- package/package.json +2 -1
- package/src/agent-execution.ts +36 -42
- package/src/background-widget.ts +25 -18
- package/src/decoders.ts +2 -1
- package/src/host-navigator.ts +58 -14
- package/src/host-view.ts +93 -37
- package/src/host.ts +51 -21
- package/src/index.ts +3 -1
- package/src/registry.ts +2 -1
- package/src/roles.ts +326 -0
- package/src/settings.ts +206 -0
- package/src/trajectory.ts +76 -7
- package/src/types.ts +1 -1
- package/src/utils.ts +8 -1
- package/src/validation.ts +12 -356
- package/subagents/README.md +1 -1
- package/subagents/src/contracts.ts +4 -0
- package/subagents/src/index.ts +3 -2
- package/subagents/src/manager.ts +28 -10
- package/subagents/src/navigator.ts +336 -180
- package/subagents/src/view.ts +97 -28
- package/trajectory/src/assets/index.html +347 -231
- package/trajectory/src/assets/prism.min.js +13 -0
- package/trajectory/src/export.ts +4 -2
- package/trajectory/src/index.ts +118 -38
- package/trajectory/src/server.ts +112 -12
package/dist/trajectory/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import { mkdir as mkdir3, open as open3, readFile as readFile6, rm as rm5 } from
|
|
|
5
5
|
import { existsSync } from "node:fs";
|
|
6
6
|
import { dirname as dirname5, join as join8 } from "node:path";
|
|
7
7
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
8
|
-
import { getAgentDir as
|
|
8
|
+
import { getAgentDir as getAgentDir4 } from "@earendil-works/pi-coding-agent";
|
|
9
9
|
|
|
10
10
|
// src/trajectory-host-handle.ts
|
|
11
11
|
var TRAJECTORY_HOST_KEY = /* @__PURE__ */ Symbol.for("pi-extensible-workflows.trajectory-host");
|
|
@@ -260,6 +260,12 @@ function resourcePatternHasMagic(pattern) {
|
|
|
260
260
|
function loadLaunchSnapshot(input) {
|
|
261
261
|
return deepFreeze(structuredClone(input));
|
|
262
262
|
}
|
|
263
|
+
function validateSchema(schema, at = "schema") {
|
|
264
|
+
if (!object(schema) || Object.getPrototypeOf(schema) !== Object.prototype || !jsonValue(schema)) fail("INVALID_SCHEMA", `${at} must be a plain JSON-compatible Schema object`);
|
|
265
|
+
if (typeof schema.type !== "string" && !Array.isArray(schema.type) && schema.$ref === void 0 && schema.anyOf === void 0 && schema.oneOf === void 0 && schema.allOf === void 0 && schema.const === void 0 && schema.enum === void 0) fail("INVALID_SCHEMA", `${at} has no JSON Schema shape`);
|
|
266
|
+
if (schema.required !== void 0 && (!Array.isArray(schema.required) || schema.required.some((key) => typeof key !== "string"))) fail("INVALID_SCHEMA", `${at}.required must be an array of strings`);
|
|
267
|
+
if (schema.properties !== void 0 && !object(schema.properties)) fail("INVALID_SCHEMA", `${at}.properties must be an object`);
|
|
268
|
+
}
|
|
263
269
|
|
|
264
270
|
// src/decoders.ts
|
|
265
271
|
var INVALID_PERSISTED_VALUE = /* @__PURE__ */ Symbol("invalid persisted value");
|
|
@@ -394,7 +400,7 @@ function decodeWorkflowExtensions(value) {
|
|
|
394
400
|
}
|
|
395
401
|
if (namespace === "trajectory") {
|
|
396
402
|
if (!object(raw) || Object.keys(raw).some((key) => key !== "port" && key !== "themes") || raw.port !== void 0 && (typeof raw.port !== "number" || !Number.isSafeInteger(raw.port) || raw.port < 1 || raw.port > 65535) || raw.themes !== void 0 && typeof raw.themes !== "boolean") return void 0;
|
|
397
|
-
normalized.trajectory = { ...raw.port === void 0 ? {} : { port: raw.port }
|
|
403
|
+
normalized.trajectory = { ...raw.port === void 0 ? {} : { port: raw.port } };
|
|
398
404
|
continue;
|
|
399
405
|
}
|
|
400
406
|
if (!jsonValue(raw)) return void 0;
|
|
@@ -1012,8 +1018,8 @@ async function listRunIds(cwd, sessionId, home = homedir2(), cleanTemps = true)
|
|
|
1012
1018
|
// src/trajectory.ts
|
|
1013
1019
|
import { open as open2, readFile as readFile4, readdir as readdir3, stat as stat3 } from "node:fs/promises";
|
|
1014
1020
|
import { homedir as homedir5 } from "node:os";
|
|
1015
|
-
import { basename as
|
|
1016
|
-
import { createBashToolDefinition, createEditToolDefinition, createFindToolDefinition, createGrepToolDefinition, createLsToolDefinition, createReadToolDefinition, createWriteToolDefinition, DefaultPackageManager, getAgentDir as
|
|
1021
|
+
import { basename as basename3, dirname as dirname4, join as join6, resolve as resolve4 } from "node:path";
|
|
1022
|
+
import { createBashToolDefinition, createEditToolDefinition, createFindToolDefinition, createGrepToolDefinition, createLsToolDefinition, createReadToolDefinition, createWriteToolDefinition, DefaultPackageManager, getAgentDir as getAgentDir3, SettingsManager, DEFAULT_MAX_BYTES } from "@earendil-works/pi-coding-agent";
|
|
1017
1023
|
|
|
1018
1024
|
// src/store.ts
|
|
1019
1025
|
import { execFile as execFile2 } from "node:child_process";
|
|
@@ -1878,7 +1884,7 @@ var RunStore = class _RunStore {
|
|
|
1878
1884
|
|
|
1879
1885
|
// src/host-view.ts
|
|
1880
1886
|
import { keyHint, truncateToVisualLines } from "@earendil-works/pi-coding-agent";
|
|
1881
|
-
import { truncateToWidth as truncateToWidth2 } from "@earendil-works/pi-tui";
|
|
1887
|
+
import { truncateToWidth as truncateToWidth2, visibleWidth as visibleWidth2 } from "@earendil-works/pi-tui";
|
|
1882
1888
|
|
|
1883
1889
|
// src/background-widget.ts
|
|
1884
1890
|
import { isKeyRelease, Key, matchesKey, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
@@ -1892,19 +1898,208 @@ var ANSI_SGR = new RegExp(ANSI_SGR_SOURCE);
|
|
|
1892
1898
|
import { Type } from "@earendil-works/pi-ai";
|
|
1893
1899
|
|
|
1894
1900
|
// src/validation.ts
|
|
1895
|
-
import { mkdirSync, readFileSync as readFileSync2, readdirSync, statSync } from "node:fs";
|
|
1896
|
-
import { homedir as homedir4 } from "node:os";
|
|
1897
|
-
import { basename as basename3, dirname as dirname3, extname, join as join5, resolve as resolve3 } from "node:path";
|
|
1898
|
-
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
1899
1901
|
import * as acorn from "acorn";
|
|
1900
|
-
|
|
1902
|
+
|
|
1903
|
+
// src/roles.ts
|
|
1904
|
+
import { getAgentDir as getAgentDir2, parseFrontmatter } from "@earendil-works/pi-coding-agent";
|
|
1901
1905
|
|
|
1902
1906
|
// src/registry.ts
|
|
1903
|
-
import { readFileSync } from "node:fs";
|
|
1904
|
-
import { basename as basename2, dirname as
|
|
1905
|
-
import { fileURLToPath } from "node:url";
|
|
1907
|
+
import { readFileSync as readFileSync2 } from "node:fs";
|
|
1908
|
+
import { basename as basename2, dirname as dirname3, isAbsolute, join as join5 } from "node:path";
|
|
1909
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
1906
1910
|
import { Value } from "typebox/value";
|
|
1907
1911
|
|
|
1912
|
+
// src/settings.ts
|
|
1913
|
+
import { mkdirSync, readFileSync } from "node:fs";
|
|
1914
|
+
import { homedir as homedir4 } from "node:os";
|
|
1915
|
+
import { dirname as dirname2, join as join4, resolve as resolve3 } from "node:path";
|
|
1916
|
+
import { fileURLToPath } from "node:url";
|
|
1917
|
+
import { getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
1918
|
+
var ROLE_DIRECTORY = "pi-extensible-workflows";
|
|
1919
|
+
var DEFAULT_SETTINGS = Object.freeze({ concurrency: 8, backgroundWidget: true });
|
|
1920
|
+
function workflowSettingsPath(agentDir = getAgentDir()) {
|
|
1921
|
+
return join4(agentDir, ROLE_DIRECTORY, "settings.json");
|
|
1922
|
+
}
|
|
1923
|
+
function normalizedResourcePath(value, settingsPath) {
|
|
1924
|
+
if (value === "*") return value;
|
|
1925
|
+
let expanded = value === "~" ? homedir4() : value.startsWith("~/") || value.startsWith("~\\") ? join4(homedir4(), value.slice(2)) : value;
|
|
1926
|
+
if (expanded.startsWith("file://")) expanded = fileURLToPath(expanded);
|
|
1927
|
+
const resolved = resolve3(dirname2(settingsPath), expanded);
|
|
1928
|
+
if (expanded === "**" || expanded.startsWith("**/") || expanded.startsWith("**\\")) return expanded;
|
|
1929
|
+
if (resourcePatternHasMagic(expanded)) {
|
|
1930
|
+
const magicIndex = resolved.search(/[*?\x5b\x5d{}()]/);
|
|
1931
|
+
const separatorIndex = Math.max(resolved.lastIndexOf("/", magicIndex), resolved.lastIndexOf("\\", magicIndex));
|
|
1932
|
+
const rootBoundary = separatorIndex === 0 || separatorIndex === 2 && /^[A-Za-z]:[\\/]/.test(resolved);
|
|
1933
|
+
const prefix = rootBoundary ? resolved.slice(0, separatorIndex + 1) : separatorIndex >= 0 ? resolved.slice(0, separatorIndex) : resolved;
|
|
1934
|
+
const suffix = rootBoundary ? resolved.slice(separatorIndex + 1) : separatorIndex >= 0 ? resolved.slice(separatorIndex) : "";
|
|
1935
|
+
return `${canonicalPath(prefix)}${suffix}`;
|
|
1936
|
+
}
|
|
1937
|
+
return canonicalPath(resolved);
|
|
1938
|
+
}
|
|
1939
|
+
function validateSelectorList(value, path, kind, errorCode2 = "INVALID_SETTINGS", normalizeExtensions = true) {
|
|
1940
|
+
if (value === void 0) return void 0;
|
|
1941
|
+
if (!Array.isArray(value)) fail(errorCode2, `${path}.${kind} must be an array`);
|
|
1942
|
+
const normalized = [];
|
|
1943
|
+
for (const [index, entry] of value.entries()) {
|
|
1944
|
+
if (typeof entry !== "string" || !entry.trim()) fail(errorCode2, `${path}.${kind}[${String(index)}] must be a non-empty string`);
|
|
1945
|
+
let selector = entry.trim();
|
|
1946
|
+
if (kind === "extensions" && normalizeExtensions) {
|
|
1947
|
+
const negated = selector.startsWith("!");
|
|
1948
|
+
const body = negated ? selector.slice(1) : selector;
|
|
1949
|
+
if (!body) fail(errorCode2, `${path}.${kind}[${String(index)}] must be a valid minimatch pattern: Empty minimatch pattern ${JSON.stringify(selector)}`);
|
|
1950
|
+
try {
|
|
1951
|
+
selector = `${negated ? "!" : ""}${normalizedResourcePath(body, path)}`;
|
|
1952
|
+
} catch (error) {
|
|
1953
|
+
fail(errorCode2, `${path}.${kind}[${String(index)}] must be a valid path: ${errorText(error)}`);
|
|
1954
|
+
}
|
|
1955
|
+
}
|
|
1956
|
+
try {
|
|
1957
|
+
validateResourcePattern(selector);
|
|
1958
|
+
} catch (error) {
|
|
1959
|
+
fail(errorCode2, `${path}.${kind}[${String(index)}] must be a valid minimatch pattern: ${errorText(error)}`);
|
|
1960
|
+
}
|
|
1961
|
+
normalized.push(selector);
|
|
1962
|
+
}
|
|
1963
|
+
return Object.freeze(normalized);
|
|
1964
|
+
}
|
|
1965
|
+
function validateWorktreePostCreateCommand(value, settingsPath) {
|
|
1966
|
+
if (value === void 0) return void 0;
|
|
1967
|
+
if (!Array.isArray(value) || value.length === 0) fail("INVALID_SETTINGS", `${settingsPath}.worktreePostCreateCommand must be a non-empty array`);
|
|
1968
|
+
return Object.freeze(value.map((entry, index) => {
|
|
1969
|
+
if (typeof entry !== "string" || !entry.trim()) fail("INVALID_SETTINGS", `${settingsPath}.worktreePostCreateCommand[${String(index)}] must be a non-empty string`);
|
|
1970
|
+
return entry;
|
|
1971
|
+
}));
|
|
1972
|
+
}
|
|
1973
|
+
function selectorsFromSettings(settings) {
|
|
1974
|
+
return {
|
|
1975
|
+
...settings.skills === void 0 ? {} : { skills: settings.skills },
|
|
1976
|
+
...settings.extensions === void 0 ? {} : { extensions: settings.extensions },
|
|
1977
|
+
...settings.tools === void 0 ? {} : { tools: settings.tools }
|
|
1978
|
+
};
|
|
1979
|
+
}
|
|
1980
|
+
function selectorSet(value) {
|
|
1981
|
+
return { skills: [...value?.skills ?? []], extensions: [...value?.extensions ?? []], ...value?.tools === void 0 ? {} : { tools: [...value.tools] } };
|
|
1982
|
+
}
|
|
1983
|
+
function validateWorkflowExtensionSettings(value, settingsPath, errorCode2 = "INVALID_SETTINGS") {
|
|
1984
|
+
if (value === void 0) return void 0;
|
|
1985
|
+
const base = `${settingsPath}.extensionSettings`;
|
|
1986
|
+
if (!object(value)) fail(errorCode2, `${base} must be an object`);
|
|
1987
|
+
const normalized = {};
|
|
1988
|
+
for (const [namespace, raw] of Object.entries(value)) {
|
|
1989
|
+
if (!validWorkflowExtensionNamespace(namespace)) fail(errorCode2, `${base} contains an invalid namespace: ${namespace}`);
|
|
1990
|
+
if (namespace === "herdr") {
|
|
1991
|
+
if (!object(raw)) fail(errorCode2, `${base}.herdr must be an object`);
|
|
1992
|
+
if (Object.keys(raw).some((key) => key !== "enableFullyInspectableMode")) fail(errorCode2, `${base}.herdr contains an unsupported setting`);
|
|
1993
|
+
if (raw.enableFullyInspectableMode !== void 0 && typeof raw.enableFullyInspectableMode !== "boolean") fail(errorCode2, `${base}.herdr.enableFullyInspectableMode must be a boolean`);
|
|
1994
|
+
normalized.herdr = Object.freeze({ ...raw.enableFullyInspectableMode === void 0 ? {} : { enableFullyInspectableMode: raw.enableFullyInspectableMode } });
|
|
1995
|
+
continue;
|
|
1996
|
+
}
|
|
1997
|
+
if (namespace === "trajectory") {
|
|
1998
|
+
if (!object(raw)) fail(errorCode2, `${base}.trajectory must be an object`);
|
|
1999
|
+
if (Object.keys(raw).some((key) => key !== "port")) fail(errorCode2, `${base}.trajectory contains an unsupported setting`);
|
|
2000
|
+
if (raw.port !== void 0 && (!positiveInteger(raw.port) || raw.port > 65535)) fail(errorCode2, `${base}.trajectory.port must be an integer from 1 to 65535`);
|
|
2001
|
+
normalized.trajectory = Object.freeze({ ...raw.port === void 0 ? {} : { port: raw.port } });
|
|
2002
|
+
continue;
|
|
2003
|
+
}
|
|
2004
|
+
if (!jsonValue(raw)) fail(errorCode2, `${base}.${namespace} must be JSON-compatible`);
|
|
2005
|
+
normalized[namespace] = structuredClone(raw);
|
|
2006
|
+
}
|
|
2007
|
+
return deepFreeze(normalized);
|
|
2008
|
+
}
|
|
2009
|
+
function positiveRetentionInteger(value) {
|
|
2010
|
+
return positiveInteger(value) && Number.isSafeInteger(value);
|
|
2011
|
+
}
|
|
2012
|
+
function validateRetention(value, settingsPath) {
|
|
2013
|
+
if (value === void 0) return void 0;
|
|
2014
|
+
const base = `${settingsPath}.retention`;
|
|
2015
|
+
if (!object(value)) fail("INVALID_SETTINGS", `${base} must be an object`);
|
|
2016
|
+
const unknown = Object.keys(value).find((key) => key !== "olderThanDays" && key !== "maxTerminalRuns");
|
|
2017
|
+
if (unknown) fail("INVALID_SETTINGS", `Unknown retention setting at ${base}: ${unknown}`);
|
|
2018
|
+
if (value.olderThanDays !== void 0 && !positiveRetentionInteger(value.olderThanDays)) fail("INVALID_SETTINGS", `${base}.olderThanDays must be a positive integer`);
|
|
2019
|
+
if (value.maxTerminalRuns !== void 0 && !positiveRetentionInteger(value.maxTerminalRuns)) fail("INVALID_SETTINGS", `${base}.maxTerminalRuns must be a positive integer`);
|
|
2020
|
+
return Object.freeze({ ...value.olderThanDays === void 0 ? {} : { olderThanDays: value.olderThanDays }, ...value.maxTerminalRuns === void 0 ? {} : { maxTerminalRuns: value.maxTerminalRuns } });
|
|
2021
|
+
}
|
|
2022
|
+
function parseSettings(path, partial) {
|
|
2023
|
+
let parsed;
|
|
2024
|
+
try {
|
|
2025
|
+
parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
2026
|
+
} catch (error) {
|
|
2027
|
+
if (isNodeError(error, "ENOENT")) return partial ? Object.freeze({}) : DEFAULT_SETTINGS;
|
|
2028
|
+
fail("CONFIG_ERROR", `Invalid workflow settings JSON at ${path}: ${errorText(error)}`);
|
|
2029
|
+
}
|
|
2030
|
+
if (!object(parsed)) fail("INVALID_SETTINGS", `Workflow settings at ${path} must be an object`);
|
|
2031
|
+
const allowed = /* @__PURE__ */ new Set(["concurrency", "modelAliases", "skills", "extensions", "extensionSettings", "tools", "retention", "worktreePostCreateCommand", ...partial ? [] : ["backgroundWidget"]]);
|
|
2032
|
+
const unknown = Object.keys(parsed).find((key) => !allowed.has(key));
|
|
2033
|
+
if (Object.prototype.hasOwnProperty.call(parsed, "disabledAgentResources")) fail("INVALID_SETTINGS", `disabledAgentResources is no longer supported; use skills, extensions, and tools selectors (settings: ${path})`);
|
|
2034
|
+
if (unknown) fail("INVALID_SETTINGS", `Unknown workflow setting at ${path}: ${unknown}`);
|
|
2035
|
+
const concurrency = parsed.concurrency === void 0 ? partial ? void 0 : DEFAULT_SETTINGS.concurrency : parsed.concurrency;
|
|
2036
|
+
if (concurrency !== void 0 && (!positiveInteger(concurrency) || concurrency > 16)) fail("INVALID_SETTINGS", `${path}.concurrency must be an integer from 1 to 16`);
|
|
2037
|
+
const backgroundWidget = parsed.backgroundWidget === void 0 ? partial ? void 0 : DEFAULT_SETTINGS.backgroundWidget : parsed.backgroundWidget;
|
|
2038
|
+
if (backgroundWidget !== void 0 && typeof backgroundWidget !== "boolean") fail("INVALID_SETTINGS", `${path}.backgroundWidget must be a boolean`);
|
|
2039
|
+
const modelAliases = parsed.modelAliases === void 0 ? void 0 : validateModelAliases(parsed.modelAliases, path);
|
|
2040
|
+
const skills = validateSelectorList(parsed.skills, path, "skills");
|
|
2041
|
+
const tools = validateSelectorList(parsed.tools, path, "tools");
|
|
2042
|
+
const extensions = validateSelectorList(parsed.extensions, path, "extensions");
|
|
2043
|
+
const extensionSettings = parsed.extensionSettings === void 0 ? void 0 : validateWorkflowExtensionSettings(parsed.extensionSettings, path, "INVALID_SETTINGS");
|
|
2044
|
+
const retention = validateRetention(parsed.retention, path);
|
|
2045
|
+
const worktreePostCreateCommand = validateWorktreePostCreateCommand(parsed.worktreePostCreateCommand, path);
|
|
2046
|
+
return Object.freeze({
|
|
2047
|
+
...concurrency === void 0 ? {} : { concurrency },
|
|
2048
|
+
...backgroundWidget === void 0 ? {} : { backgroundWidget },
|
|
2049
|
+
...modelAliases === void 0 ? {} : { modelAliases },
|
|
2050
|
+
...skills === void 0 ? {} : { skills },
|
|
2051
|
+
...extensions === void 0 ? {} : { extensions },
|
|
2052
|
+
...extensionSettings === void 0 ? {} : { extensionSettings },
|
|
2053
|
+
...tools === void 0 ? {} : { tools },
|
|
2054
|
+
...retention === void 0 ? {} : { retention },
|
|
2055
|
+
...worktreePostCreateCommand === void 0 ? {} : { worktreePostCreateCommand }
|
|
2056
|
+
});
|
|
2057
|
+
}
|
|
2058
|
+
function loadSettings(path = workflowSettingsPath()) {
|
|
2059
|
+
return parseSettings(path, false);
|
|
2060
|
+
}
|
|
2061
|
+
function loadSettingsOverrides(path) {
|
|
2062
|
+
return parseSettings(path, true);
|
|
2063
|
+
}
|
|
2064
|
+
function resolveWorkflowSettings(cwd, projectTrusted, globalSettingsPath = workflowSettingsPath()) {
|
|
2065
|
+
const projectSettingsPath = workflowProjectSettingsPath(cwd);
|
|
2066
|
+
const global = loadSettings(globalSettingsPath);
|
|
2067
|
+
const project = projectTrusted ? loadSettingsOverrides(projectSettingsPath) : Object.freeze({});
|
|
2068
|
+
const projectHas = (key) => Object.prototype.hasOwnProperty.call(project, key);
|
|
2069
|
+
const sourceFor = (key) => projectHas(key) ? projectSettingsPath : globalSettingsPath;
|
|
2070
|
+
const globalSelectors = selectorsFromSettings(global);
|
|
2071
|
+
const projectSelectors = selectorsFromSettings(project);
|
|
2072
|
+
const effectiveSelectors = selectorSet({
|
|
2073
|
+
skills: [...globalSelectors.skills ?? [], ...projectSelectors.skills ?? []],
|
|
2074
|
+
extensions: [...globalSelectors.extensions ?? [], ...projectSelectors.extensions ?? []],
|
|
2075
|
+
...globalSelectors.tools === void 0 && projectSelectors.tools === void 0 ? {} : { tools: [...globalSelectors.tools ?? [], ...projectSelectors.tools ?? []] }
|
|
2076
|
+
});
|
|
2077
|
+
const hasExtensionSelectors = global.extensions !== void 0 || project.extensions !== void 0;
|
|
2078
|
+
const extensionSettings = projectHas("extensionSettings") ? project.extensionSettings : global.extensionSettings;
|
|
2079
|
+
const sources = {
|
|
2080
|
+
concurrency: projectHas("concurrency") ? projectSettingsPath : globalSettingsPath,
|
|
2081
|
+
modelAliases: projectHas("modelAliases") ? projectSettingsPath : globalSettingsPath,
|
|
2082
|
+
skills: sourceFor("skills"),
|
|
2083
|
+
extensions: sourceFor("extensions"),
|
|
2084
|
+
tools: sourceFor("tools"),
|
|
2085
|
+
...extensionSettings === void 0 ? {} : { extensionSettings: projectHas("extensionSettings") ? projectSettingsPath : globalSettingsPath },
|
|
2086
|
+
...project.retention === void 0 && global.retention === void 0 ? {} : { retention: project.retention === void 0 ? globalSettingsPath : projectSettingsPath },
|
|
2087
|
+
...projectHas("worktreePostCreateCommand") || global.worktreePostCreateCommand !== void 0 ? { worktreePostCreateCommand: projectHas("worktreePostCreateCommand") ? projectSettingsPath : globalSettingsPath } : {}
|
|
2088
|
+
};
|
|
2089
|
+
const effective = Object.freeze({
|
|
2090
|
+
concurrency: project.concurrency ?? global.concurrency,
|
|
2091
|
+
backgroundWidget: global.backgroundWidget ?? true,
|
|
2092
|
+
...projectHas("modelAliases") ? { modelAliases: project.modelAliases } : global.modelAliases === void 0 ? {} : { modelAliases: global.modelAliases },
|
|
2093
|
+
...effectiveSelectors.skills.length ? { skills: effectiveSelectors.skills } : global.skills !== void 0 || project.skills !== void 0 ? { skills: effectiveSelectors.skills } : {},
|
|
2094
|
+
...hasExtensionSelectors ? { extensions: effectiveSelectors.extensions } : {},
|
|
2095
|
+
...extensionSettings === void 0 ? {} : { extensionSettings },
|
|
2096
|
+
...effectiveSelectors.tools?.length ? { tools: effectiveSelectors.tools } : global.tools !== void 0 || project.tools !== void 0 ? { tools: effectiveSelectors.tools } : {},
|
|
2097
|
+
...(project.retention ?? global.retention) === void 0 ? {} : { retention: project.retention ?? global.retention },
|
|
2098
|
+
...projectHas("worktreePostCreateCommand") ? { worktreePostCreateCommand: project.worktreePostCreateCommand } : global.worktreePostCreateCommand === void 0 ? {} : { worktreePostCreateCommand: global.worktreePostCreateCommand }
|
|
2099
|
+
});
|
|
2100
|
+
return { globalSettingsPath, projectSettingsPath, projectTrusted, global, project, effective, sources };
|
|
2101
|
+
}
|
|
2102
|
+
|
|
1908
2103
|
// src/package-identity.ts
|
|
1909
2104
|
var CORE_PACKAGE_NAME = "@marcoscale98/pi-extensible-workflows";
|
|
1910
2105
|
var CORE_PACKAGE_COMPATIBILITY_NAME = "pi-extensible-workflows";
|
|
@@ -1922,10 +2117,10 @@ function normalizeRoleDirectory(value) {
|
|
|
1922
2117
|
try {
|
|
1923
2118
|
if (value instanceof URL) {
|
|
1924
2119
|
if (value.protocol !== "file:") fail("INVALID_METADATA", "Workflow role directories require file URLs or absolute filesystem paths");
|
|
1925
|
-
return
|
|
2120
|
+
return fileURLToPath2(value);
|
|
1926
2121
|
}
|
|
1927
2122
|
if (typeof value === "string") {
|
|
1928
|
-
if (value.startsWith("file:")) return
|
|
2123
|
+
if (value.startsWith("file:")) return fileURLToPath2(value);
|
|
1929
2124
|
if (isAbsolute(value)) return value;
|
|
1930
2125
|
}
|
|
1931
2126
|
} catch (error) {
|
|
@@ -1935,12 +2130,12 @@ function normalizeRoleDirectory(value) {
|
|
|
1935
2130
|
}
|
|
1936
2131
|
function isBuiltinRoleDirectory(path) {
|
|
1937
2132
|
const canonical = canonicalPath(path);
|
|
1938
|
-
const starterDirectory =
|
|
2133
|
+
const starterDirectory = dirname3(canonical);
|
|
1939
2134
|
if (basename2(canonical) !== "roles" || basename2(starterDirectory) !== "starter") return false;
|
|
1940
|
-
const distributionDirectory =
|
|
1941
|
-
const packageRoot = basename2(distributionDirectory) === "dist" ?
|
|
2135
|
+
const distributionDirectory = dirname3(starterDirectory);
|
|
2136
|
+
const packageRoot = basename2(distributionDirectory) === "dist" ? dirname3(distributionDirectory) : distributionDirectory;
|
|
1942
2137
|
try {
|
|
1943
|
-
const metadata = JSON.parse(
|
|
2138
|
+
const metadata = JSON.parse(readFileSync2(join5(packageRoot, "package.json"), "utf8"));
|
|
1944
2139
|
return object(metadata) && isCorePackageName(metadata.name);
|
|
1945
2140
|
} catch {
|
|
1946
2141
|
return false;
|
|
@@ -2214,199 +2409,6 @@ function beginWorkflowExtensionLoading() {
|
|
|
2214
2409
|
}
|
|
2215
2410
|
beginWorkflowExtensionLoading();
|
|
2216
2411
|
|
|
2217
|
-
// src/validation.ts
|
|
2218
|
-
var DEFAULT_SETTINGS = Object.freeze({ concurrency: 8, backgroundWidget: true });
|
|
2219
|
-
function workflowSettingsPath(agentDir = getAgentDir()) {
|
|
2220
|
-
return join5(agentDir, ROLE_DIRECTORY, "settings.json");
|
|
2221
|
-
}
|
|
2222
|
-
function normalizedResourcePath(value, settingsPath) {
|
|
2223
|
-
if (value === "*") return value;
|
|
2224
|
-
let expanded = value === "~" ? homedir4() : value.startsWith("~/") || value.startsWith("~\\") ? join5(homedir4(), value.slice(2)) : value;
|
|
2225
|
-
if (expanded.startsWith("file://")) expanded = fileURLToPath2(expanded);
|
|
2226
|
-
const resolved = resolve3(dirname3(settingsPath), expanded);
|
|
2227
|
-
if (expanded === "**" || expanded.startsWith("**/") || expanded.startsWith("**\\")) return expanded;
|
|
2228
|
-
if (resourcePatternHasMagic(expanded)) {
|
|
2229
|
-
const magicIndex = resolved.search(/[*?\x5b\x5d{}()]/);
|
|
2230
|
-
const separatorIndex = Math.max(resolved.lastIndexOf("/", magicIndex), resolved.lastIndexOf("\\", magicIndex));
|
|
2231
|
-
const rootBoundary = separatorIndex === 0 || separatorIndex === 2 && /^[A-Za-z]:[\\/]/.test(resolved);
|
|
2232
|
-
const prefix = rootBoundary ? resolved.slice(0, separatorIndex + 1) : separatorIndex >= 0 ? resolved.slice(0, separatorIndex) : resolved;
|
|
2233
|
-
const suffix = rootBoundary ? resolved.slice(separatorIndex + 1) : separatorIndex >= 0 ? resolved.slice(separatorIndex) : "";
|
|
2234
|
-
return `${canonicalPath(prefix)}${suffix}`;
|
|
2235
|
-
}
|
|
2236
|
-
return canonicalPath(resolved);
|
|
2237
|
-
}
|
|
2238
|
-
function validateSelectorList(value, path, kind, errorCode2 = "INVALID_SETTINGS", normalizeExtensions = true) {
|
|
2239
|
-
if (value === void 0) return void 0;
|
|
2240
|
-
if (!Array.isArray(value)) fail(errorCode2, `${path}.${kind} must be an array`);
|
|
2241
|
-
const normalized = [];
|
|
2242
|
-
for (const [index, entry] of value.entries()) {
|
|
2243
|
-
if (typeof entry !== "string" || !entry.trim()) fail(errorCode2, `${path}.${kind}[${String(index)}] must be a non-empty string`);
|
|
2244
|
-
let selector = entry.trim();
|
|
2245
|
-
if (kind === "extensions" && normalizeExtensions) {
|
|
2246
|
-
const negated = selector.startsWith("!");
|
|
2247
|
-
const body = negated ? selector.slice(1) : selector;
|
|
2248
|
-
if (!body) fail(errorCode2, `${path}.${kind}[${String(index)}] must be a valid minimatch pattern: Empty minimatch pattern ${JSON.stringify(selector)}`);
|
|
2249
|
-
try {
|
|
2250
|
-
selector = `${negated ? "!" : ""}${normalizedResourcePath(body, path)}`;
|
|
2251
|
-
} catch (error) {
|
|
2252
|
-
fail(errorCode2, `${path}.${kind}[${String(index)}] must be a valid path: ${errorText(error)}`);
|
|
2253
|
-
}
|
|
2254
|
-
}
|
|
2255
|
-
try {
|
|
2256
|
-
validateResourcePattern(selector);
|
|
2257
|
-
} catch (error) {
|
|
2258
|
-
fail(errorCode2, `${path}.${kind}[${String(index)}] must be a valid minimatch pattern: ${errorText(error)}`);
|
|
2259
|
-
}
|
|
2260
|
-
normalized.push(selector);
|
|
2261
|
-
}
|
|
2262
|
-
return Object.freeze(normalized);
|
|
2263
|
-
}
|
|
2264
|
-
function validateWorktreePostCreateCommand(value, settingsPath) {
|
|
2265
|
-
if (value === void 0) return void 0;
|
|
2266
|
-
if (!Array.isArray(value) || value.length === 0) fail("INVALID_SETTINGS", `${settingsPath}.worktreePostCreateCommand must be a non-empty array`);
|
|
2267
|
-
return Object.freeze(value.map((entry, index) => {
|
|
2268
|
-
if (typeof entry !== "string" || !entry.trim()) fail("INVALID_SETTINGS", `${settingsPath}.worktreePostCreateCommand[${String(index)}] must be a non-empty string`);
|
|
2269
|
-
return entry;
|
|
2270
|
-
}));
|
|
2271
|
-
}
|
|
2272
|
-
function selectorsFromSettings(settings) {
|
|
2273
|
-
return {
|
|
2274
|
-
...settings.skills === void 0 ? {} : { skills: settings.skills },
|
|
2275
|
-
...settings.extensions === void 0 ? {} : { extensions: settings.extensions },
|
|
2276
|
-
...settings.tools === void 0 ? {} : { tools: settings.tools }
|
|
2277
|
-
};
|
|
2278
|
-
}
|
|
2279
|
-
function selectorSet(value) {
|
|
2280
|
-
return { skills: [...value?.skills ?? []], extensions: [...value?.extensions ?? []], ...value?.tools === void 0 ? {} : { tools: [...value.tools] } };
|
|
2281
|
-
}
|
|
2282
|
-
function validateWorkflowExtensionSettings(value, settingsPath, errorCode2 = "INVALID_SETTINGS", applyDefaults = true) {
|
|
2283
|
-
if (value === void 0) return void 0;
|
|
2284
|
-
const base = `${settingsPath}.extensionSettings`;
|
|
2285
|
-
if (!object(value)) fail(errorCode2, `${base} must be an object`);
|
|
2286
|
-
const normalized = {};
|
|
2287
|
-
for (const [namespace, raw] of Object.entries(value)) {
|
|
2288
|
-
if (!validWorkflowExtensionNamespace(namespace)) fail(errorCode2, `${base} contains an invalid namespace: ${namespace}`);
|
|
2289
|
-
if (namespace === "herdr") {
|
|
2290
|
-
if (!object(raw)) fail(errorCode2, `${base}.herdr must be an object`);
|
|
2291
|
-
if (Object.keys(raw).some((key) => key !== "enableFullyInspectableMode")) fail(errorCode2, `${base}.herdr contains an unsupported setting`);
|
|
2292
|
-
if (raw.enableFullyInspectableMode !== void 0 && typeof raw.enableFullyInspectableMode !== "boolean") fail(errorCode2, `${base}.herdr.enableFullyInspectableMode must be a boolean`);
|
|
2293
|
-
normalized.herdr = Object.freeze({ ...raw.enableFullyInspectableMode === void 0 ? {} : { enableFullyInspectableMode: raw.enableFullyInspectableMode } });
|
|
2294
|
-
continue;
|
|
2295
|
-
}
|
|
2296
|
-
if (namespace === "trajectory") {
|
|
2297
|
-
if (!object(raw)) fail(errorCode2, `${base}.trajectory must be an object`);
|
|
2298
|
-
if (Object.keys(raw).some((key) => key !== "port" && key !== "themes")) fail(errorCode2, `${base}.trajectory contains an unsupported setting`);
|
|
2299
|
-
if (raw.port !== void 0 && (!positiveInteger(raw.port) || raw.port > 65535)) fail(errorCode2, `${base}.trajectory.port must be an integer from 1 to 65535`);
|
|
2300
|
-
if (raw.themes !== void 0 && typeof raw.themes !== "boolean") fail(errorCode2, `${base}.trajectory.themes must be a boolean`);
|
|
2301
|
-
normalized.trajectory = Object.freeze({ ...raw.port === void 0 ? {} : { port: raw.port }, ...raw.themes === void 0 ? applyDefaults ? { themes: false } : {} : { themes: raw.themes } });
|
|
2302
|
-
continue;
|
|
2303
|
-
}
|
|
2304
|
-
if (!jsonValue(raw)) fail(errorCode2, `${base}.${namespace} must be JSON-compatible`);
|
|
2305
|
-
normalized[namespace] = structuredClone(raw);
|
|
2306
|
-
}
|
|
2307
|
-
return deepFreeze(normalized);
|
|
2308
|
-
}
|
|
2309
|
-
function positiveRetentionInteger(value) {
|
|
2310
|
-
return positiveInteger(value) && Number.isSafeInteger(value);
|
|
2311
|
-
}
|
|
2312
|
-
function validateRetention(value, settingsPath) {
|
|
2313
|
-
if (value === void 0) return void 0;
|
|
2314
|
-
const base = `${settingsPath}.retention`;
|
|
2315
|
-
if (!object(value)) fail("INVALID_SETTINGS", `${base} must be an object`);
|
|
2316
|
-
const unknown = Object.keys(value).find((key) => key !== "olderThanDays" && key !== "maxTerminalRuns");
|
|
2317
|
-
if (unknown) fail("INVALID_SETTINGS", `Unknown retention setting at ${base}: ${unknown}`);
|
|
2318
|
-
if (value.olderThanDays !== void 0 && !positiveRetentionInteger(value.olderThanDays)) fail("INVALID_SETTINGS", `${base}.olderThanDays must be a positive integer`);
|
|
2319
|
-
if (value.maxTerminalRuns !== void 0 && !positiveRetentionInteger(value.maxTerminalRuns)) fail("INVALID_SETTINGS", `${base}.maxTerminalRuns must be a positive integer`);
|
|
2320
|
-
return Object.freeze({ ...value.olderThanDays === void 0 ? {} : { olderThanDays: value.olderThanDays }, ...value.maxTerminalRuns === void 0 ? {} : { maxTerminalRuns: value.maxTerminalRuns } });
|
|
2321
|
-
}
|
|
2322
|
-
function parseSettings(path, partial) {
|
|
2323
|
-
let parsed;
|
|
2324
|
-
try {
|
|
2325
|
-
parsed = JSON.parse(readFileSync2(path, "utf8"));
|
|
2326
|
-
} catch (error) {
|
|
2327
|
-
if (isNodeError(error, "ENOENT")) return partial ? Object.freeze({}) : DEFAULT_SETTINGS;
|
|
2328
|
-
fail("CONFIG_ERROR", `Invalid workflow settings JSON at ${path}: ${errorText(error)}`);
|
|
2329
|
-
}
|
|
2330
|
-
if (!object(parsed)) fail("INVALID_SETTINGS", `Workflow settings at ${path} must be an object`);
|
|
2331
|
-
const allowed = /* @__PURE__ */ new Set(["concurrency", "modelAliases", "skills", "extensions", "extensionSettings", "tools", "retention", "worktreePostCreateCommand", ...partial ? [] : ["backgroundWidget"]]);
|
|
2332
|
-
const unknown = Object.keys(parsed).find((key) => !allowed.has(key));
|
|
2333
|
-
if (Object.prototype.hasOwnProperty.call(parsed, "disabledAgentResources")) fail("INVALID_SETTINGS", `disabledAgentResources is no longer supported; use skills, extensions, and tools selectors (settings: ${path})`);
|
|
2334
|
-
if (unknown) fail("INVALID_SETTINGS", `Unknown workflow setting at ${path}: ${unknown}`);
|
|
2335
|
-
const concurrency = parsed.concurrency === void 0 ? partial ? void 0 : DEFAULT_SETTINGS.concurrency : parsed.concurrency;
|
|
2336
|
-
if (concurrency !== void 0 && (!positiveInteger(concurrency) || concurrency > 16)) fail("INVALID_SETTINGS", `${path}.concurrency must be an integer from 1 to 16`);
|
|
2337
|
-
const backgroundWidget = parsed.backgroundWidget === void 0 ? partial ? void 0 : DEFAULT_SETTINGS.backgroundWidget : parsed.backgroundWidget;
|
|
2338
|
-
if (backgroundWidget !== void 0 && typeof backgroundWidget !== "boolean") fail("INVALID_SETTINGS", `${path}.backgroundWidget must be a boolean`);
|
|
2339
|
-
const modelAliases = parsed.modelAliases === void 0 ? void 0 : validateModelAliases(parsed.modelAliases, path);
|
|
2340
|
-
const skills = validateSelectorList(parsed.skills, path, "skills");
|
|
2341
|
-
const tools = validateSelectorList(parsed.tools, path, "tools");
|
|
2342
|
-
const extensions = validateSelectorList(parsed.extensions, path, "extensions");
|
|
2343
|
-
const extensionSettings = parsed.extensionSettings === void 0 ? void 0 : validateWorkflowExtensionSettings(parsed.extensionSettings, path, "INVALID_SETTINGS", !partial);
|
|
2344
|
-
const retention = validateRetention(parsed.retention, path);
|
|
2345
|
-
const worktreePostCreateCommand = validateWorktreePostCreateCommand(parsed.worktreePostCreateCommand, path);
|
|
2346
|
-
return Object.freeze({
|
|
2347
|
-
...concurrency === void 0 ? {} : { concurrency },
|
|
2348
|
-
...backgroundWidget === void 0 ? {} : { backgroundWidget },
|
|
2349
|
-
...modelAliases === void 0 ? {} : { modelAliases },
|
|
2350
|
-
...skills === void 0 ? {} : { skills },
|
|
2351
|
-
...extensions === void 0 ? {} : { extensions },
|
|
2352
|
-
...extensionSettings === void 0 ? {} : { extensionSettings },
|
|
2353
|
-
...tools === void 0 ? {} : { tools },
|
|
2354
|
-
...retention === void 0 ? {} : { retention },
|
|
2355
|
-
...worktreePostCreateCommand === void 0 ? {} : { worktreePostCreateCommand }
|
|
2356
|
-
});
|
|
2357
|
-
}
|
|
2358
|
-
function loadSettings(path = workflowSettingsPath()) {
|
|
2359
|
-
return parseSettings(path, false);
|
|
2360
|
-
}
|
|
2361
|
-
function loadSettingsOverrides(path) {
|
|
2362
|
-
return parseSettings(path, true);
|
|
2363
|
-
}
|
|
2364
|
-
function resolveWorkflowSettings(cwd, projectTrusted, globalSettingsPath = workflowSettingsPath()) {
|
|
2365
|
-
const projectSettingsPath = workflowProjectSettingsPath(cwd);
|
|
2366
|
-
const global = loadSettings(globalSettingsPath);
|
|
2367
|
-
const project = projectTrusted ? loadSettingsOverrides(projectSettingsPath) : Object.freeze({});
|
|
2368
|
-
const projectHas = (key) => Object.prototype.hasOwnProperty.call(project, key);
|
|
2369
|
-
const sourceFor = (key) => projectHas(key) ? projectSettingsPath : globalSettingsPath;
|
|
2370
|
-
const globalSelectors = selectorsFromSettings(global);
|
|
2371
|
-
const projectSelectors = selectorsFromSettings(project);
|
|
2372
|
-
const effectiveSelectors = selectorSet({
|
|
2373
|
-
skills: [...globalSelectors.skills ?? [], ...projectSelectors.skills ?? []],
|
|
2374
|
-
extensions: [...globalSelectors.extensions ?? [], ...projectSelectors.extensions ?? []],
|
|
2375
|
-
...globalSelectors.tools === void 0 && projectSelectors.tools === void 0 ? {} : { tools: [...globalSelectors.tools ?? [], ...projectSelectors.tools ?? []] }
|
|
2376
|
-
});
|
|
2377
|
-
const hasExtensionSelectors = global.extensions !== void 0 || project.extensions !== void 0;
|
|
2378
|
-
const extensionSettings = projectHas("extensionSettings") ? project.extensionSettings : global.extensionSettings;
|
|
2379
|
-
const sources = {
|
|
2380
|
-
concurrency: projectHas("concurrency") ? projectSettingsPath : globalSettingsPath,
|
|
2381
|
-
modelAliases: projectHas("modelAliases") ? projectSettingsPath : globalSettingsPath,
|
|
2382
|
-
skills: sourceFor("skills"),
|
|
2383
|
-
extensions: sourceFor("extensions"),
|
|
2384
|
-
tools: sourceFor("tools"),
|
|
2385
|
-
...extensionSettings === void 0 ? {} : { extensionSettings: projectHas("extensionSettings") ? projectSettingsPath : globalSettingsPath },
|
|
2386
|
-
...project.retention === void 0 && global.retention === void 0 ? {} : { retention: project.retention === void 0 ? globalSettingsPath : projectSettingsPath },
|
|
2387
|
-
...projectHas("worktreePostCreateCommand") || global.worktreePostCreateCommand !== void 0 ? { worktreePostCreateCommand: projectHas("worktreePostCreateCommand") ? projectSettingsPath : globalSettingsPath } : {}
|
|
2388
|
-
};
|
|
2389
|
-
const effective = Object.freeze({
|
|
2390
|
-
concurrency: project.concurrency ?? global.concurrency,
|
|
2391
|
-
backgroundWidget: global.backgroundWidget ?? true,
|
|
2392
|
-
...projectHas("modelAliases") ? { modelAliases: project.modelAliases } : global.modelAliases === void 0 ? {} : { modelAliases: global.modelAliases },
|
|
2393
|
-
...effectiveSelectors.skills.length ? { skills: effectiveSelectors.skills } : global.skills !== void 0 || project.skills !== void 0 ? { skills: effectiveSelectors.skills } : {},
|
|
2394
|
-
...hasExtensionSelectors ? { extensions: effectiveSelectors.extensions } : {},
|
|
2395
|
-
...extensionSettings === void 0 ? {} : { extensionSettings },
|
|
2396
|
-
...effectiveSelectors.tools?.length ? { tools: effectiveSelectors.tools } : global.tools !== void 0 || project.tools !== void 0 ? { tools: effectiveSelectors.tools } : {},
|
|
2397
|
-
...(project.retention ?? global.retention) === void 0 ? {} : { retention: project.retention ?? global.retention },
|
|
2398
|
-
...projectHas("worktreePostCreateCommand") ? { worktreePostCreateCommand: project.worktreePostCreateCommand } : global.worktreePostCreateCommand === void 0 ? {} : { worktreePostCreateCommand: global.worktreePostCreateCommand }
|
|
2399
|
-
});
|
|
2400
|
-
return { globalSettingsPath, projectSettingsPath, projectTrusted, global, project, effective, sources };
|
|
2401
|
-
}
|
|
2402
|
-
var ROLE_DIRECTORY = "pi-extensible-workflows";
|
|
2403
|
-
function validateSchema(schema, at = "schema") {
|
|
2404
|
-
if (!object(schema) || Object.getPrototypeOf(schema) !== Object.prototype || !jsonValue(schema)) fail("INVALID_SCHEMA", `${at} must be a plain JSON-compatible Schema object`);
|
|
2405
|
-
if (typeof schema.type !== "string" && !Array.isArray(schema.type) && schema.$ref === void 0 && schema.anyOf === void 0 && schema.oneOf === void 0 && schema.allOf === void 0 && schema.const === void 0 && schema.enum === void 0) fail("INVALID_SCHEMA", `${at} has no JSON Schema shape`);
|
|
2406
|
-
if (schema.required !== void 0 && (!Array.isArray(schema.required) || schema.required.some((key) => typeof key !== "string"))) fail("INVALID_SCHEMA", `${at}.required must be an array of strings`);
|
|
2407
|
-
if (schema.properties !== void 0 && !object(schema.properties)) fail("INVALID_SCHEMA", `${at}.properties must be an object`);
|
|
2408
|
-
}
|
|
2409
|
-
|
|
2410
2412
|
// subagents/src/contracts.ts
|
|
2411
2413
|
import { Value as Value2 } from "typebox/value";
|
|
2412
2414
|
var SUBAGENT_MAX_RETRIES = 255;
|
|
@@ -2605,15 +2607,15 @@ function canonicalExtensionSelector(selector, base) {
|
|
|
2605
2607
|
return `${negated ? "!" : ""}${canonicalPath(resolved)}`;
|
|
2606
2608
|
}
|
|
2607
2609
|
function skillNameFromPath(path) {
|
|
2608
|
-
const file =
|
|
2609
|
-
return file.toLowerCase() === "skill.md" ?
|
|
2610
|
+
const file = basename3(path);
|
|
2611
|
+
return file.toLowerCase() === "skill.md" ? basename3(dirname4(path)) : file;
|
|
2610
2612
|
}
|
|
2611
2613
|
var discoveredResourcesByCwd = /* @__PURE__ */ new Map();
|
|
2612
2614
|
async function discoveredResources(cwd) {
|
|
2613
2615
|
const cached = discoveredResourcesByCwd.get(cwd);
|
|
2614
2616
|
if (cached) return cached;
|
|
2615
2617
|
const pending = (async () => {
|
|
2616
|
-
const agentDir =
|
|
2618
|
+
const agentDir = getAgentDir3();
|
|
2617
2619
|
const settingsManager = SettingsManager.create(cwd, agentDir, { projectTrusted: false });
|
|
2618
2620
|
const packageManager = new DefaultPackageManager({ cwd, agentDir, settingsManager });
|
|
2619
2621
|
const resolved = await packageManager.resolve();
|
|
@@ -2660,11 +2662,46 @@ function withoutAgentActivities(run) {
|
|
|
2660
2662
|
});
|
|
2661
2663
|
return agents.every((agent, index) => agent === run.agents[index]) ? run : { ...run, agents };
|
|
2662
2664
|
}
|
|
2665
|
+
function serializedJsonBytes(value) {
|
|
2666
|
+
const serialized = JSON.stringify(value);
|
|
2667
|
+
return Buffer.byteLength(serialized, "utf8");
|
|
2668
|
+
}
|
|
2669
|
+
function failedAgentOutput(agent) {
|
|
2670
|
+
const error = [...agent.attemptDetails ?? []].reverse().find((attempt) => attempt.error)?.error;
|
|
2671
|
+
const status = agent.state === "cancelled" ? "cancelled" : "failed";
|
|
2672
|
+
return { status, code: error?.code ?? (status === "cancelled" ? "CANCELLED" : "AGENT_FAILED"), message: error?.message ?? `Agent ${agent.state}` };
|
|
2673
|
+
}
|
|
2674
|
+
function outputForAgent(agent, operation) {
|
|
2675
|
+
if (operation !== void 0) {
|
|
2676
|
+
const bytes = serializedJsonBytes(operation.value);
|
|
2677
|
+
return bytes > DEFAULT_MAX_BYTES ? { status: "truncated", kind: "result", bytes } : { status: "available", value: operation.value, bytes };
|
|
2678
|
+
}
|
|
2679
|
+
if (agent.state === "failed" || agent.state === "cancelled") return failedAgentOutput(agent);
|
|
2680
|
+
if (agent.state === "completed") return { status: "unavailable" };
|
|
2681
|
+
return { status: "pending" };
|
|
2682
|
+
}
|
|
2683
|
+
function applyTrajectoryAgentOutputs(run, operations) {
|
|
2684
|
+
const byPath = new Map(operations.map((operation) => [operation.path, operation]));
|
|
2685
|
+
const agents = run.agents.map((agent) => ({ ...agent, output: outputForAgent(agent, agent.resultPath === void 0 ? void 0 : byPath.get(agent.resultPath)) }));
|
|
2686
|
+
return { ...run, agents };
|
|
2687
|
+
}
|
|
2688
|
+
function overlayTrajectoryRun(run, overlay) {
|
|
2689
|
+
const overlaid = overlay(run);
|
|
2690
|
+
const outputs = new Map(run.agents.map((agent) => [agent.id, agent.output]));
|
|
2691
|
+
const agents = overlaid.agents.map((agent) => {
|
|
2692
|
+
const previous = outputs.get(agent.id);
|
|
2693
|
+
const output = previous?.status === "available" || previous?.status === "truncated" ? previous : outputForAgent(agent, void 0);
|
|
2694
|
+
return { ...agent, output };
|
|
2695
|
+
});
|
|
2696
|
+
return { ...overlaid, agents };
|
|
2697
|
+
}
|
|
2663
2698
|
async function loadTrajectoryRun(store, includeTranscripts = true) {
|
|
2664
2699
|
const value = await store.load();
|
|
2665
2700
|
const summary = await store.loadSummary().catch(() => void 0);
|
|
2666
2701
|
const prompts = await store.systemPrompts().catch(() => []);
|
|
2667
|
-
const
|
|
2702
|
+
const prepared = withoutAgentActivities(await withResolvedResources(withPiToolDescriptions(applySystemPrompts(value.run, prompts)), store.cwd));
|
|
2703
|
+
const operations = await store.replayableOperations().catch(() => []);
|
|
2704
|
+
const run = applyTrajectoryAgentOutputs(prepared, operations);
|
|
2668
2705
|
return { run, snapshot: value.snapshot, awaiting: await store.awaitingCheckpoints(), ...summary?.createdAt === void 0 ? {} : { createdAt: summary.createdAt }, transcripts: includeTranscripts ? await runTranscripts(run) : {} };
|
|
2669
2706
|
}
|
|
2670
2707
|
async function loadTrajectoryRuns(cwd, sessionId, home = homedir5(), overlay) {
|
|
@@ -2672,7 +2709,7 @@ async function loadTrajectoryRuns(cwd, sessionId, home = homedir5(), overlay) {
|
|
|
2672
2709
|
for (const runId of await listRunIds(cwd, sessionId, home, false)) {
|
|
2673
2710
|
try {
|
|
2674
2711
|
const value = await loadTrajectoryRun(new RunStore(cwd, sessionId, runId, home));
|
|
2675
|
-
loaded.push(overlay ? { ...value, run:
|
|
2712
|
+
loaded.push(overlay ? { ...value, run: overlayTrajectoryRun(value.run, overlay) } : value);
|
|
2676
2713
|
} catch {
|
|
2677
2714
|
}
|
|
2678
2715
|
}
|
|
@@ -2695,15 +2732,16 @@ async function exportTrajectoryRunHtml(options) {
|
|
|
2695
2732
|
const run = runs.find((candidate) => candidate.run.id === options.runId);
|
|
2696
2733
|
if (!run) throw new Error(`Workflow run ${options.runId} was not found for session ${options.sessionId}`);
|
|
2697
2734
|
const assets = new URL("./assets/", import.meta.url);
|
|
2698
|
-
const [html, marked, morphdom, favicon] = await Promise.all([
|
|
2735
|
+
const [html, marked, morphdom, prism, favicon] = await Promise.all([
|
|
2699
2736
|
readFile5(new URL("index.html", assets), "utf8"),
|
|
2700
2737
|
readFile5(new URL("marked.min.js", assets)),
|
|
2701
2738
|
readFile5(new URL("morphdom.min.js", assets)),
|
|
2739
|
+
readFile5(new URL("prism.min.js", assets)),
|
|
2702
2740
|
readFile5(new URL("favicon.png", assets))
|
|
2703
2741
|
]);
|
|
2704
2742
|
const state = {
|
|
2705
2743
|
type: "state",
|
|
2706
|
-
publishers: [{ id: `export-${options.runId}`, title: `run ${options.runId.slice(0, 8)}`, cwd: options.cwd, sessionId: options.sessionId,
|
|
2744
|
+
publishers: [{ id: `export-${options.runId}`, title: `run ${options.runId.slice(0, 8)}`, cwd: options.cwd, sessionId: options.sessionId, connected: true, runs: [run], subagents: [] }],
|
|
2707
2745
|
updatedAt: Date.now()
|
|
2708
2746
|
};
|
|
2709
2747
|
const script = (source) => `<script src="data:text/javascript;base64,${source.toString("base64")}"></script>`;
|
|
@@ -2711,6 +2749,7 @@ async function exportTrajectoryRunHtml(options) {
|
|
|
2711
2749
|
output = inlineAsset(output, '<link rel="icon" type="image/png" href="./favicon.png" />', `<link rel="icon" type="image/png" href="data:image/png;base64,${favicon.toString("base64")}" />`);
|
|
2712
2750
|
output = inlineAsset(output, '<script src="./marked.min.js"></script>', script(marked));
|
|
2713
2751
|
output = inlineAsset(output, '<script src="./morphdom.min.js"></script>', script(morphdom));
|
|
2752
|
+
output = inlineAsset(output, '<script src="./prism.min.js"></script>', script(prism));
|
|
2714
2753
|
output = inlineAsset(output, '<body data-view="run">', `<body data-view="run">
|
|
2715
2754
|
<script>window.__PIEWF_STATIC__ = ${JSON.stringify(state).replace(/</g, "\\u003c")};</script>`);
|
|
2716
2755
|
return output;
|
|
@@ -2771,14 +2810,20 @@ function trajectoryPort(value) {
|
|
|
2771
2810
|
function delay(ms) {
|
|
2772
2811
|
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
2773
2812
|
}
|
|
2774
|
-
async function
|
|
2813
|
+
async function serverHealth(port) {
|
|
2775
2814
|
try {
|
|
2776
2815
|
const response = await fetch(`http://127.0.0.1:${String(port)}/health`, { signal: AbortSignal.timeout(300) });
|
|
2777
|
-
|
|
2816
|
+
if (!response.ok) return void 0;
|
|
2817
|
+
const body = await response.json().catch(() => void 0);
|
|
2818
|
+
if (!object(body)) return {};
|
|
2819
|
+
return { ...positiveInteger(body.pid) ? { pid: body.pid } : {}, ...typeof body.fingerprint === "string" ? { fingerprint: body.fingerprint } : {}, ...positiveInteger(body.startedAt) ? { startedAt: body.startedAt } : {} };
|
|
2778
2820
|
} catch {
|
|
2779
|
-
return
|
|
2821
|
+
return void 0;
|
|
2780
2822
|
}
|
|
2781
2823
|
}
|
|
2824
|
+
async function serverHealthy(port) {
|
|
2825
|
+
return await serverHealth(port) !== void 0;
|
|
2826
|
+
}
|
|
2782
2827
|
function signalProcess(pid, signal) {
|
|
2783
2828
|
try {
|
|
2784
2829
|
process.kill(pid, signal);
|
|
@@ -2811,23 +2856,27 @@ async function readLock(path) {
|
|
|
2811
2856
|
return void 0;
|
|
2812
2857
|
}
|
|
2813
2858
|
}
|
|
2814
|
-
async function waitForServer(port) {
|
|
2859
|
+
async function waitForServer(port, fingerprint) {
|
|
2860
|
+
let foreign = false;
|
|
2815
2861
|
for (let attempt = 0; attempt < 60; attempt += 1) {
|
|
2816
|
-
|
|
2862
|
+
const health = await serverHealth(port);
|
|
2863
|
+
if (health?.fingerprint === fingerprint) return;
|
|
2864
|
+
foreign = health !== void 0;
|
|
2817
2865
|
await delay(50);
|
|
2818
2866
|
}
|
|
2819
|
-
throw new Error(`Trajectory server did not start on port ${String(port)}`);
|
|
2867
|
+
throw new Error(foreign ? `Trajectory port ${String(port)} is held by another Trajectory server; stop it and retry` : `Trajectory server did not start on port ${String(port)}`);
|
|
2820
2868
|
}
|
|
2821
2869
|
async function resolveExistingServer(lockPath, existing, fingerprint) {
|
|
2822
|
-
|
|
2823
|
-
|
|
2870
|
+
const health = await serverHealth(existing.port);
|
|
2871
|
+
if (health) {
|
|
2872
|
+
if (existing.fingerprint === fingerprint && health.fingerprint === fingerprint) return existing;
|
|
2824
2873
|
await stopStaleServer(existing);
|
|
2825
2874
|
await rm5(lockPath, { force: true });
|
|
2826
2875
|
return void 0;
|
|
2827
2876
|
}
|
|
2828
2877
|
if (await processAlive(existing.pid, existing.startedAt)) {
|
|
2829
2878
|
try {
|
|
2830
|
-
await waitForServer(existing.port);
|
|
2879
|
+
await waitForServer(existing.port, fingerprint);
|
|
2831
2880
|
return existing;
|
|
2832
2881
|
} catch {
|
|
2833
2882
|
await stopStaleServer(existing);
|
|
@@ -2870,13 +2919,15 @@ async function ensureTrajectoryServer(agentDir, configuredPort) {
|
|
|
2870
2919
|
} finally {
|
|
2871
2920
|
await lockHandle?.close();
|
|
2872
2921
|
}
|
|
2922
|
+
const occupant = await serverHealth(configuredPort);
|
|
2923
|
+
if (occupant?.pid !== void 0 && occupant.fingerprint !== fingerprint) await stopStaleServer({ pid: occupant.pid, port: configuredPort, ...occupant.startedAt === void 0 ? {} : { startedAt: occupant.startedAt } });
|
|
2873
2924
|
try {
|
|
2874
2925
|
const child = spawn(process.versions.bun ? "node" : process.execPath, [serverPath, "--port", String(configuredPort), "--lock", lockPath, "--fingerprint", fingerprint], { detached: true, stdio: "ignore" });
|
|
2875
2926
|
const startupError = new Promise((_resolve, reject) => {
|
|
2876
2927
|
child.once("error", reject);
|
|
2877
2928
|
});
|
|
2878
2929
|
child.unref();
|
|
2879
|
-
await Promise.race([waitForServer(configuredPort), startupError]);
|
|
2930
|
+
await Promise.race([waitForServer(configuredPort, fingerprint), startupError]);
|
|
2880
2931
|
return { port: configuredPort };
|
|
2881
2932
|
} catch (error) {
|
|
2882
2933
|
await rm5(lockPath, { force: true });
|
|
@@ -2907,6 +2958,8 @@ var MAX_FRAME_BYTES = 32 * 1024 * 1024;
|
|
|
2907
2958
|
var MAX_LIVE_STATE_BYTES = MAX_FRAME_BYTES - 1024;
|
|
2908
2959
|
var MAX_TRANSCRIPT_REQUESTS = 64;
|
|
2909
2960
|
var TRANSCRIPT_REQUEST_TIMEOUT_MS = 1e4;
|
|
2961
|
+
var ACTIVE_POLL_MS = 1e3;
|
|
2962
|
+
var IDLE_POLL_MS = 1e4;
|
|
2910
2963
|
var RECONNECT_INITIAL_DELAY_MS = 100;
|
|
2911
2964
|
var RECONNECT_MAX_DELAY_MS = 5e3;
|
|
2912
2965
|
function isTimingEntry(value) {
|
|
@@ -2923,44 +2976,89 @@ var MAX_LIVE_OBJECT_KEYS = 64;
|
|
|
2923
2976
|
var LIVE_METADATA_ARRAY_KEYS = /* @__PURE__ */ new Set(["agents", "runs", "subagents"]);
|
|
2924
2977
|
var LIVE_TRUNCATABLE_ARRAY_KEYS = /* @__PURE__ */ new Set(["events", "phaseHistory"]);
|
|
2925
2978
|
var LIVE_METADATA_OBJECT_KEYS = /* @__PURE__ */ new Set(["transcripts"]);
|
|
2979
|
+
function liveValueWillBeBounded(value, key = "", depth = 0) {
|
|
2980
|
+
if (typeof value === "string") return Buffer.byteLength(value) > MAX_LIVE_STRING_BYTES;
|
|
2981
|
+
if (typeof value !== "object" || value === null) return false;
|
|
2982
|
+
if (depth >= 12) return true;
|
|
2983
|
+
if (Array.isArray(value)) {
|
|
2984
|
+
const maxEntries = LIVE_TRUNCATABLE_ARRAY_KEYS.has(key) ? MAX_LIVE_ARRAY_ENTRIES - 1 : MAX_LIVE_ARRAY_ENTRIES;
|
|
2985
|
+
if (key === "attemptDetails" && value.length > 8 || !LIVE_METADATA_ARRAY_KEYS.has(key) && value.length > maxEntries) return true;
|
|
2986
|
+
return value.some((entry) => liveValueWillBeBounded(entry, "", depth + 1));
|
|
2987
|
+
}
|
|
2988
|
+
if (!object(value)) return false;
|
|
2989
|
+
const properties = LIVE_METADATA_OBJECT_KEYS.has(key) ? Object.keys(value) : Object.keys(value).sort().slice(0, MAX_LIVE_OBJECT_KEYS);
|
|
2990
|
+
if (!LIVE_METADATA_OBJECT_KEYS.has(key) && Object.keys(value).length > MAX_LIVE_OBJECT_KEYS) return true;
|
|
2991
|
+
return properties.some((property) => liveValueWillBeBounded(value[property], property, depth + 1));
|
|
2992
|
+
}
|
|
2993
|
+
var MAX_LIVE_TIMING_BYTES = 64 * 1024;
|
|
2926
2994
|
function boundedTiming(value) {
|
|
2927
2995
|
const entries = Array.isArray(value) ? value.filter(isTimingEntry) : [];
|
|
2928
2996
|
const retained = [];
|
|
2929
2997
|
let bytes = 2;
|
|
2930
|
-
for (
|
|
2998
|
+
for (let index = entries.length - 1; index >= 0; index -= 1) {
|
|
2931
2999
|
let serialized;
|
|
2932
3000
|
try {
|
|
2933
|
-
serialized = JSON.stringify(
|
|
3001
|
+
serialized = JSON.stringify(entries[index]);
|
|
2934
3002
|
} catch {
|
|
2935
3003
|
continue;
|
|
2936
3004
|
}
|
|
2937
3005
|
const nextBytes = bytes + (retained.length ? 1 : 0) + Buffer.byteLength(serialized);
|
|
2938
|
-
if (nextBytes >=
|
|
2939
|
-
retained.push(
|
|
3006
|
+
if (nextBytes >= MAX_LIVE_TIMING_BYTES) break;
|
|
3007
|
+
retained.push(entries[index]);
|
|
2940
3008
|
bytes = nextBytes;
|
|
2941
3009
|
}
|
|
2942
|
-
return retained;
|
|
3010
|
+
return retained.reverse();
|
|
2943
3011
|
}
|
|
2944
|
-
function boundedLiveValue(value, key = "", depth = 0) {
|
|
2945
|
-
|
|
2946
|
-
if (
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
return
|
|
3012
|
+
function boundedLiveValue(value, key = "", depth = 0, bounds) {
|
|
3013
|
+
const pathLength = bounds?.path.length ?? 0;
|
|
3014
|
+
if (bounds && key) bounds.path.push(key);
|
|
3015
|
+
const argsValue = bounds !== void 0 && bounds.path.length >= 3 && bounds.path[0] === "runs" && bounds.path[1] === "snapshot" && bounds.path[2] === "args";
|
|
3016
|
+
const markArgsTruncated = () => {
|
|
3017
|
+
if (argsValue && bounds.runIndex !== void 0) bounds.argsTruncatedRuns.add(bounds.runIndex);
|
|
3018
|
+
};
|
|
3019
|
+
try {
|
|
3020
|
+
if (typeof value === "string") {
|
|
3021
|
+
if (argsValue && Buffer.byteLength(value) > MAX_LIVE_STRING_BYTES) markArgsTruncated();
|
|
3022
|
+
return boundedString(value, MAX_LIVE_STRING_BYTES);
|
|
3023
|
+
}
|
|
3024
|
+
if (typeof value === "number" || typeof value === "boolean" || value === null) return value;
|
|
3025
|
+
if (depth >= 12) {
|
|
3026
|
+
markArgsTruncated();
|
|
3027
|
+
return void 0;
|
|
3028
|
+
}
|
|
3029
|
+
if (key === "timing" && !argsValue) return boundedTiming(value);
|
|
3030
|
+
if (key === "output" && object(value) && value.status === "available") {
|
|
3031
|
+
const boundedOutput = boundedLiveValue(value.value, "value", depth + 1, bounds);
|
|
3032
|
+
return liveValueWillBeBounded(value.value, "value", depth + 1) ? { status: "truncated", kind: "result", bytes: value.bytes } : { ...value, value: boundedOutput };
|
|
3033
|
+
}
|
|
3034
|
+
if (Array.isArray(value)) {
|
|
3035
|
+
const array = value;
|
|
3036
|
+
const maxEntries = !argsValue && LIVE_TRUNCATABLE_ARRAY_KEYS.has(key) ? MAX_LIVE_ARRAY_ENTRIES - 1 : MAX_LIVE_ARRAY_ENTRIES;
|
|
3037
|
+
const entries = !argsValue && key === "attemptDetails" ? array.slice(-8) : !argsValue && LIVE_METADATA_ARRAY_KEYS.has(key) ? array : array.length <= maxEntries ? array : [...array.slice(0, 32), ...array.slice(-maxEntries + 32)];
|
|
3038
|
+
if (entries.length !== array.length) markArgsTruncated();
|
|
3039
|
+
const publisherRuns = bounds?.path.length === 1 && bounds.path[0] === "runs";
|
|
3040
|
+
const bounded = entries.map((entry, index) => {
|
|
3041
|
+
const previousRunIndex = bounds?.runIndex;
|
|
3042
|
+
if (publisherRuns) bounds.runIndex = index;
|
|
3043
|
+
const result = boundedLiveValue(entry, "", depth + 1, bounds);
|
|
3044
|
+
if (bounds) bounds.runIndex = previousRunIndex;
|
|
3045
|
+
return result;
|
|
3046
|
+
});
|
|
3047
|
+
if (entries.length !== array.length && LIVE_TRUNCATABLE_ARRAY_KEYS.has(key)) bounded.push({ type: "trajectory:truncated", field: key, omitted: array.length - entries.length });
|
|
3048
|
+
return bounded;
|
|
3049
|
+
}
|
|
3050
|
+
if (object(value)) {
|
|
3051
|
+
const result = {};
|
|
3052
|
+
const keys = Object.keys(value).sort();
|
|
3053
|
+
const properties = !argsValue && LIVE_METADATA_OBJECT_KEYS.has(key) ? keys : keys.slice(0, MAX_LIVE_OBJECT_KEYS);
|
|
3054
|
+
if (properties.length !== keys.length) markArgsTruncated();
|
|
3055
|
+
for (const property of properties) result[property] = boundedLiveValue(value[property], property, depth + 1, bounds);
|
|
3056
|
+
return result;
|
|
3057
|
+
}
|
|
3058
|
+
return void 0;
|
|
3059
|
+
} finally {
|
|
3060
|
+
if (bounds) bounds.path.length = pathLength;
|
|
2962
3061
|
}
|
|
2963
|
-
return void 0;
|
|
2964
3062
|
}
|
|
2965
3063
|
function transcriptRevisionProjection(value, depth = 0) {
|
|
2966
3064
|
if (depth >= 8) return typeof value === "string" ? boundedString(value, 1024) : typeof value === "number" || typeof value === "boolean" || value === null ? value : void 0;
|
|
@@ -3007,7 +3105,19 @@ function projectPublisher(metadata, publisher, revisions) {
|
|
|
3007
3105
|
return { ...publisher, runs: metadata.runs.map((run) => projectRun(run, `${publisherId2} ${run.run.id}`, revisions)), subagents: metadata.subagents.map((subagent) => projectSubagent(subagent, `${publisherId2} subagent ${subagent.id}`, revisions)) };
|
|
3008
3106
|
}
|
|
3009
3107
|
function minimalStatePublisher(publisher) {
|
|
3010
|
-
|
|
3108
|
+
const bounds = { argsTruncatedRuns: /* @__PURE__ */ new Set(), path: [], runIndex: void 0 };
|
|
3109
|
+
const bounded = boundedLiveValue(publisher, "", 0, bounds) ?? {};
|
|
3110
|
+
const sourceRuns = Array.isArray(publisher.runs) ? publisher.runs : [];
|
|
3111
|
+
const boundedRuns = Array.isArray(bounded.runs) ? bounded.runs : [];
|
|
3112
|
+
if (!sourceRuns.length || !boundedRuns.length) return bounded;
|
|
3113
|
+
const runs = boundedRuns.map((run, index) => {
|
|
3114
|
+
const sourceRun = sourceRuns[index];
|
|
3115
|
+
const sourceSnapshot = object(sourceRun) && object(sourceRun.snapshot) ? sourceRun.snapshot : void 0;
|
|
3116
|
+
const boundedSnapshot = object(run) && object(run.snapshot) ? run.snapshot : void 0;
|
|
3117
|
+
const argsUnavailable = sourceSnapshot !== void 0 && sourceSnapshot.args !== void 0 && sourceSnapshot.args !== null && (boundedSnapshot === void 0 || !Object.prototype.hasOwnProperty.call(boundedSnapshot, "args"));
|
|
3118
|
+
return (bounds.argsTruncatedRuns.has(index) || argsUnavailable) && object(run) ? { ...run, snapshotArgsTruncated: true } : run;
|
|
3119
|
+
});
|
|
3120
|
+
return { ...bounded, runs };
|
|
3011
3121
|
}
|
|
3012
3122
|
function publisherStateFrame(publisher, runs, subagents, truncated = false) {
|
|
3013
3123
|
const publisherSummary = { ...publisher };
|
|
@@ -3077,18 +3187,19 @@ function createTrajectoryController(agentDir) {
|
|
|
3077
3187
|
for (const request of pendingTranscripts.values()) clearTimeout(request.timer);
|
|
3078
3188
|
pendingTranscripts.clear();
|
|
3079
3189
|
};
|
|
3190
|
+
let viewers = 0;
|
|
3080
3191
|
const startPolling = () => {
|
|
3081
3192
|
stopPolling();
|
|
3082
3193
|
pollTimer = setInterval(() => {
|
|
3083
3194
|
void sendState().catch((error) => {
|
|
3084
3195
|
if (!closing) console.error(`Trajectory state publish failed: ${errorText(error)}`);
|
|
3085
3196
|
});
|
|
3086
|
-
},
|
|
3197
|
+
}, viewers > 0 ? ACTIVE_POLL_MS : IDLE_POLL_MS);
|
|
3087
3198
|
pollTimer.unref();
|
|
3088
3199
|
};
|
|
3089
3200
|
let stateLoad;
|
|
3090
3201
|
let lastState;
|
|
3091
|
-
const publisherValue = (input) => ({ id: publisherId(input.cwd, input.sessionId), title: `session ${input.sessionId.slice(0, 8)}`, cwd: input.cwd, sessionId: input.sessionId,
|
|
3202
|
+
const publisherValue = (input) => ({ id: publisherId(input.cwd, input.sessionId), title: `session ${input.sessionId.slice(0, 8)}`, cwd: input.cwd, sessionId: input.sessionId, connected: true });
|
|
3092
3203
|
const sendState = async () => {
|
|
3093
3204
|
const activeSocket = socket;
|
|
3094
3205
|
if (activeSocket !== void 0 && stateLoad?.socket === activeSocket) return stateLoad.task;
|
|
@@ -3244,6 +3355,14 @@ function createTrajectoryController(agentDir) {
|
|
|
3244
3355
|
established = false;
|
|
3245
3356
|
return;
|
|
3246
3357
|
}
|
|
3358
|
+
if (message.type === "publisher:viewers" && typeof message.count === "number") {
|
|
3359
|
+
const watched = viewers > 0;
|
|
3360
|
+
viewers = message.count;
|
|
3361
|
+
if (watched === viewers > 0) return;
|
|
3362
|
+
if (socket === next && !closing) startPolling();
|
|
3363
|
+
if (viewers > 0) void sendState().catch(() => void 0);
|
|
3364
|
+
return;
|
|
3365
|
+
}
|
|
3247
3366
|
if (message.type === "publisher:transcript" && typeof message.requestId === "string" && typeof message.publisherId === "string" && (typeof message.runId === "string" && typeof message.agentId === "string" || typeof message.subagentId === "string")) {
|
|
3248
3367
|
handleTranscriptRequest(next, generation, message, input);
|
|
3249
3368
|
return;
|
|
@@ -3398,7 +3517,7 @@ function createTrajectoryController(agentDir) {
|
|
|
3398
3517
|
};
|
|
3399
3518
|
}
|
|
3400
3519
|
function registerTrajectoryExtension(pi, options = {}) {
|
|
3401
|
-
const controller = options.controller ?? createTrajectoryController(options.agentDir ??
|
|
3520
|
+
const controller = options.controller ?? createTrajectoryController(options.agentDir ?? getAgentDir4());
|
|
3402
3521
|
const openUrl = options.openUrl ?? openTrajectoryUrl;
|
|
3403
3522
|
let autoAttached = false;
|
|
3404
3523
|
const notify = (context, message, level) => {
|
|
@@ -3450,6 +3569,7 @@ export {
|
|
|
3450
3569
|
createTrajectoryController,
|
|
3451
3570
|
extension as default,
|
|
3452
3571
|
exportTrajectoryRunHtml,
|
|
3572
|
+
minimalStatePublisher,
|
|
3453
3573
|
openTrajectoryUrl,
|
|
3454
3574
|
registerTrajectoryExtension,
|
|
3455
3575
|
shareTrajectoryRun,
|