@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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// trajectory/src/server.ts
|
|
2
|
-
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
+
import { createHash, randomUUID as randomUUID3 } from "node:crypto";
|
|
3
3
|
import { createServer } from "node:http";
|
|
4
|
-
import { readFile, rm
|
|
4
|
+
import { readFile as readFile3, rm as rm3 } from "node:fs/promises";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
import { URL } from "node:url";
|
|
7
7
|
|
|
@@ -18,9 +18,12 @@ function trajectoryActionError(action, target) {
|
|
|
18
18
|
return target.kind === "subagent" && (action === "checkpoint-approve" || action === "checkpoint-reject" || action === "pause" || action === "resume" || action === "share") ? `Trajectory action ${action} is not supported for subagent targets` : target.kind === "run" && action === "steer" ? "Trajectory action steer is not supported for run targets" : void 0;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
// src/
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
21
|
+
// src/io.ts
|
|
22
|
+
import { execFile } from "node:child_process";
|
|
23
|
+
import { randomUUID } from "node:crypto";
|
|
24
|
+
import { renameSync, rmSync, writeFileSync } from "node:fs";
|
|
25
|
+
import { readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
26
|
+
import { promisify } from "node:util";
|
|
24
27
|
|
|
25
28
|
// src/types.ts
|
|
26
29
|
var WORKFLOW_AGENT_STALL_THRESHOLD_MS = 10 * 60 * 1e3;
|
|
@@ -1896,12 +1899,78 @@ minimatch.escape = escape;
|
|
|
1896
1899
|
minimatch.unescape = unescape;
|
|
1897
1900
|
|
|
1898
1901
|
// src/utils.ts
|
|
1902
|
+
function object(value) {
|
|
1903
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1904
|
+
}
|
|
1899
1905
|
var ESCAPE_CHARACTER = String.fromCharCode(27);
|
|
1900
1906
|
var BELL_CHARACTER = String.fromCharCode(7);
|
|
1901
1907
|
var ANSI_ESCAPE_SEQUENCE = new RegExp(`${ESCAPE_CHARACTER}(?:\\[[0-?]*[ -/]*[@-~]|\\][^${BELL_CHARACTER}]*(?:${BELL_CHARACTER}|${ESCAPE_CHARACTER}\\\\))`, "g");
|
|
1902
1908
|
var TERMINAL_CONTROL_CHARACTER = new RegExp(`[${String.fromCharCode(0)}-${String.fromCharCode(31)}${String.fromCharCode(127)}-${String.fromCharCode(159)}]`, "g");
|
|
1909
|
+
function positiveInteger(value) {
|
|
1910
|
+
return typeof value === "number" && Number.isInteger(value) && value > 0;
|
|
1911
|
+
}
|
|
1912
|
+
function isNodeError(error, code) {
|
|
1913
|
+
return object(error) && error.code === code;
|
|
1914
|
+
}
|
|
1915
|
+
|
|
1916
|
+
// src/io.ts
|
|
1917
|
+
var execute = promisify(execFile);
|
|
1918
|
+
var RENAME_RETRY_DELAYS_MS = [10, 25, 50, 100, 200, 400, 800];
|
|
1919
|
+
var syncSleepBuffer = new Int32Array(new SharedArrayBuffer(4));
|
|
1920
|
+
function retryableRenameError(error) {
|
|
1921
|
+
return isNodeError(error, "EPERM") || isNodeError(error, "EBUSY") || isNodeError(error, "EACCES");
|
|
1922
|
+
}
|
|
1923
|
+
async function renameWithRetry(from, to) {
|
|
1924
|
+
for (let attempt = 0; ; attempt += 1) {
|
|
1925
|
+
try {
|
|
1926
|
+
await rename(from, to);
|
|
1927
|
+
return;
|
|
1928
|
+
} catch (error) {
|
|
1929
|
+
const delayMs = RENAME_RETRY_DELAYS_MS[attempt];
|
|
1930
|
+
if (!retryableRenameError(error) || delayMs === void 0) throw error;
|
|
1931
|
+
await new Promise((resolve2) => setTimeout(resolve2, delayMs));
|
|
1932
|
+
}
|
|
1933
|
+
}
|
|
1934
|
+
}
|
|
1935
|
+
function renameSyncWithRetry(from, to) {
|
|
1936
|
+
for (let attempt = 0; ; attempt += 1) {
|
|
1937
|
+
try {
|
|
1938
|
+
renameSync(from, to);
|
|
1939
|
+
return;
|
|
1940
|
+
} catch (error) {
|
|
1941
|
+
const delayMs = RENAME_RETRY_DELAYS_MS[attempt];
|
|
1942
|
+
if (!retryableRenameError(error) || delayMs === void 0) throw error;
|
|
1943
|
+
Atomics.wait(syncSleepBuffer, 0, 0, delayMs);
|
|
1944
|
+
}
|
|
1945
|
+
}
|
|
1946
|
+
}
|
|
1947
|
+
function atomicWriteFile(path2, content, sync = false) {
|
|
1948
|
+
const temporary = `${path2}.${String(process.pid)}.${randomUUID()}.tmp`;
|
|
1949
|
+
if (sync) {
|
|
1950
|
+
try {
|
|
1951
|
+
writeFileSync(temporary, content, { encoding: "utf8", mode: 384 });
|
|
1952
|
+
renameSyncWithRetry(temporary, path2);
|
|
1953
|
+
} catch (error) {
|
|
1954
|
+
try {
|
|
1955
|
+
rmSync(temporary, { force: true });
|
|
1956
|
+
} catch {
|
|
1957
|
+
}
|
|
1958
|
+
throw error;
|
|
1959
|
+
}
|
|
1960
|
+
return;
|
|
1961
|
+
}
|
|
1962
|
+
return writeFile(temporary, content, { encoding: "utf8", mode: 384 }).then(() => renameWithRetry(temporary, path2)).catch(async (error) => {
|
|
1963
|
+
try {
|
|
1964
|
+
await rm(temporary, { force: true });
|
|
1965
|
+
} catch {
|
|
1966
|
+
}
|
|
1967
|
+
throw error;
|
|
1968
|
+
});
|
|
1969
|
+
}
|
|
1903
1970
|
|
|
1904
1971
|
// src/paths.ts
|
|
1972
|
+
import { realpathSync } from "node:fs";
|
|
1973
|
+
import { basename, isAbsolute, join, relative, resolve, sep as sep2 } from "node:path";
|
|
1905
1974
|
function canonicalPath(path2) {
|
|
1906
1975
|
const absolute = resolve(path2);
|
|
1907
1976
|
try {
|
|
@@ -1914,15 +1983,148 @@ function sameFilesystemPath(left, right) {
|
|
|
1914
1983
|
return canonicalPath(left) === canonicalPath(right);
|
|
1915
1984
|
}
|
|
1916
1985
|
|
|
1986
|
+
// trajectory/src/startup-mutex.ts
|
|
1987
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
1988
|
+
import { readFileSync } from "node:fs";
|
|
1989
|
+
import { mkdir, readdir, readFile as readFile2, rm as rm2 } from "node:fs/promises";
|
|
1990
|
+
import { join as join2 } from "node:path";
|
|
1991
|
+
var bootId;
|
|
1992
|
+
function processStart(pid) {
|
|
1993
|
+
if (process.platform !== "linux") return void 0;
|
|
1994
|
+
try {
|
|
1995
|
+
bootId ??= readFileSync("/proc/sys/kernel/random/boot_id", "utf8").trim();
|
|
1996
|
+
const stat = readFileSync(`/proc/${String(pid)}/stat`, "utf8");
|
|
1997
|
+
const startTicks = stat.slice(stat.lastIndexOf(")") + 2).split(" ")[19];
|
|
1998
|
+
return startTicks === void 0 || !/^\d+$/.test(startTicks) ? void 0 : `${bootId}:${startTicks}`;
|
|
1999
|
+
} catch {
|
|
2000
|
+
return void 0;
|
|
2001
|
+
}
|
|
2002
|
+
}
|
|
2003
|
+
function processLive(identity) {
|
|
2004
|
+
try {
|
|
2005
|
+
process.kill(identity.pid, 0);
|
|
2006
|
+
} catch (error) {
|
|
2007
|
+
if (isNodeError(error, "ESRCH")) return false;
|
|
2008
|
+
}
|
|
2009
|
+
if (identity.start === void 0) return true;
|
|
2010
|
+
const current = processStart(identity.pid);
|
|
2011
|
+
return current === void 0 || current === identity.start;
|
|
2012
|
+
}
|
|
2013
|
+
function processConfirmed(identity) {
|
|
2014
|
+
return identity.start !== void 0 && processStart(identity.pid) === identity.start;
|
|
2015
|
+
}
|
|
2016
|
+
function holderDirectory(lockPath) {
|
|
2017
|
+
return `${lockPath}.startup`;
|
|
2018
|
+
}
|
|
2019
|
+
function holderPath(lockPath, token) {
|
|
2020
|
+
return join2(holderDirectory(lockPath), `${token}.json`);
|
|
2021
|
+
}
|
|
2022
|
+
function identityOf(pid) {
|
|
2023
|
+
const start = processStart(pid);
|
|
2024
|
+
return start === void 0 ? { pid } : { pid, start };
|
|
2025
|
+
}
|
|
2026
|
+
function processIdentity(value) {
|
|
2027
|
+
if (!object(value) || !positiveInteger(value.pid)) return void 0;
|
|
2028
|
+
return typeof value.start === "string" ? { pid: value.pid, start: value.start } : { pid: value.pid };
|
|
2029
|
+
}
|
|
2030
|
+
function decodeHolder(text) {
|
|
2031
|
+
try {
|
|
2032
|
+
const parsed = JSON.parse(text);
|
|
2033
|
+
const holder = processIdentity(parsed);
|
|
2034
|
+
if (holder === void 0 || !object(parsed) || typeof parsed.token !== "string") return void 0;
|
|
2035
|
+
const server = processIdentity(parsed.server);
|
|
2036
|
+
return { ...holder, token: parsed.token, ...server === void 0 ? {} : { server } };
|
|
2037
|
+
} catch {
|
|
2038
|
+
return void 0;
|
|
2039
|
+
}
|
|
2040
|
+
}
|
|
2041
|
+
function readStartupHolder(lockPath, token) {
|
|
2042
|
+
try {
|
|
2043
|
+
return decodeHolder(readFileSync(holderPath(lockPath, token), "utf8"));
|
|
2044
|
+
} catch (error) {
|
|
2045
|
+
if (isNodeError(error, "ENOENT")) return void 0;
|
|
2046
|
+
throw error;
|
|
2047
|
+
}
|
|
2048
|
+
}
|
|
2049
|
+
async function serverPending(lockPath, server) {
|
|
2050
|
+
if (!processLive(server)) return false;
|
|
2051
|
+
let text;
|
|
2052
|
+
try {
|
|
2053
|
+
text = await readFile2(lockPath, "utf8");
|
|
2054
|
+
} catch (error) {
|
|
2055
|
+
if (isNodeError(error, "ENOENT")) return true;
|
|
2056
|
+
throw error;
|
|
2057
|
+
}
|
|
2058
|
+
try {
|
|
2059
|
+
const lock = JSON.parse(text);
|
|
2060
|
+
return !(object(lock) && lock.pid === server.pid);
|
|
2061
|
+
} catch {
|
|
2062
|
+
return true;
|
|
2063
|
+
}
|
|
2064
|
+
}
|
|
2065
|
+
async function holderLive(lockPath, path2, read) {
|
|
2066
|
+
if (processLive(read)) return true;
|
|
2067
|
+
let holder;
|
|
2068
|
+
try {
|
|
2069
|
+
holder = decodeHolder(await readFile2(path2, "utf8"));
|
|
2070
|
+
} catch (error) {
|
|
2071
|
+
if (isNodeError(error, "ENOENT")) return false;
|
|
2072
|
+
throw error;
|
|
2073
|
+
}
|
|
2074
|
+
if (holder?.server === void 0 || !await serverPending(lockPath, holder.server)) return false;
|
|
2075
|
+
if (!processConfirmed(holder.server)) return true;
|
|
2076
|
+
try {
|
|
2077
|
+
process.kill(holder.server.pid, "SIGKILL");
|
|
2078
|
+
} catch (error) {
|
|
2079
|
+
if (!isNodeError(error, "ESRCH")) throw error;
|
|
2080
|
+
}
|
|
2081
|
+
return true;
|
|
2082
|
+
}
|
|
2083
|
+
async function tryAcquireStartupMutex(lockPath) {
|
|
2084
|
+
const directory = holderDirectory(lockPath);
|
|
2085
|
+
await mkdir(directory, { recursive: true, mode: 448 });
|
|
2086
|
+
const token = randomUUID2();
|
|
2087
|
+
const own = `${token}.json`;
|
|
2088
|
+
await atomicWriteFile(join2(directory, own), `${JSON.stringify({ ...identityOf(process.pid), token })}
|
|
2089
|
+
`);
|
|
2090
|
+
let contended = false;
|
|
2091
|
+
try {
|
|
2092
|
+
for (const name of await readdir(directory)) {
|
|
2093
|
+
if (name === own || !name.endsWith(".json")) continue;
|
|
2094
|
+
const path2 = join2(directory, name);
|
|
2095
|
+
let holder;
|
|
2096
|
+
try {
|
|
2097
|
+
holder = decodeHolder(await readFile2(path2, "utf8"));
|
|
2098
|
+
} catch (error) {
|
|
2099
|
+
if (isNodeError(error, "ENOENT")) continue;
|
|
2100
|
+
throw error;
|
|
2101
|
+
}
|
|
2102
|
+
if (holder !== void 0 && await holderLive(lockPath, path2, holder)) contended = true;
|
|
2103
|
+
else await rm2(path2, { force: true });
|
|
2104
|
+
}
|
|
2105
|
+
} catch (error) {
|
|
2106
|
+
await rm2(join2(directory, own), { force: true });
|
|
2107
|
+
throw error;
|
|
2108
|
+
}
|
|
2109
|
+
if (!contended) return token;
|
|
2110
|
+
await rm2(join2(directory, own), { force: true });
|
|
2111
|
+
return void 0;
|
|
2112
|
+
}
|
|
2113
|
+
async function releaseStartupMutex(lockPath, token) {
|
|
2114
|
+
await rm2(holderPath(lockPath, token), { force: true });
|
|
2115
|
+
}
|
|
2116
|
+
|
|
2117
|
+
// src/tool-timing.ts
|
|
2118
|
+
var TOOL_TIMING_ENTRY_TYPE = "pi-workflows:tool-timing";
|
|
2119
|
+
|
|
1917
2120
|
// trajectory/src/server.ts
|
|
1918
2121
|
var TRAJECTORY_IDLE_EXIT_MS = 5 * 60 * 1e3;
|
|
1919
2122
|
var MAX_FRAME_BYTES = 32 * 1024 * 1024;
|
|
1920
2123
|
var MAX_PENDING_REQUESTS = 128;
|
|
1921
2124
|
var TRANSCRIPT_REQUEST_TIMEOUT_MS = 1e4;
|
|
1922
2125
|
var ACTION_REQUEST_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
1923
|
-
var TIMING_ENTRY_TYPE = "pi-workflows:tool-timing";
|
|
1924
2126
|
function isTimingEntry(value) {
|
|
1925
|
-
return Boolean(value && typeof value === "object" && !Array.isArray(value) && value.type === "custom" && value.customType ===
|
|
2127
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value) && value.type === "custom" && value.customType === TOOL_TIMING_ENTRY_TYPE);
|
|
1926
2128
|
}
|
|
1927
2129
|
function compactTranscript(value) {
|
|
1928
2130
|
if (Array.isArray(value)) return value.filter(isTimingEntry);
|
|
@@ -2231,7 +2433,7 @@ function createTrajectoryServer(port, lockPath, options = {}) {
|
|
|
2231
2433
|
return requests;
|
|
2232
2434
|
};
|
|
2233
2435
|
const hasPendingRequest = (requests, requestId) => [...requests.values()].some((request) => request.requestId === requestId);
|
|
2234
|
-
const publisherRequestIdFor = (requestId) => [...pending.values()].some((requests) => requests.has(requestId)) ?
|
|
2436
|
+
const publisherRequestIdFor = (requestId) => [...pending.values()].some((requests) => requests.has(requestId)) ? randomUUID3() : requestId;
|
|
2235
2437
|
const errorResponse = (_publisherRequestId, request, status, error) => request.kind === "action" ? { type: "action-result", requestId: request.requestId, ok: false, error } : { type: "transcript", requestId: request.requestId, publisherId: request.publisherId, ...request.target.runId === void 0 ? {} : { runId: request.target.runId }, ...request.target.agentId === void 0 ? {} : { agentId: request.target.agentId }, ...request.target.subagentId === void 0 ? {} : { subagentId: request.target.subagentId }, ok: false, status, revision: request.target.revision ?? 0, error };
|
|
2236
2438
|
const clearPending = (client, error) => {
|
|
2237
2439
|
const own = pending.get(client);
|
|
@@ -2260,21 +2462,45 @@ function createTrajectoryServer(port, lockPath, options = {}) {
|
|
|
2260
2462
|
if (!requests.size) pending.delete(browser);
|
|
2261
2463
|
emit(browser, errorResponse(requestId, request, "failed", error));
|
|
2262
2464
|
};
|
|
2465
|
+
const busy = () => closed || [...publishers.values()].some(({ value }) => value.connected === true);
|
|
2263
2466
|
const scheduleIdleExit = () => {
|
|
2264
|
-
if (
|
|
2467
|
+
if (busy() || idleTimer !== void 0) return;
|
|
2265
2468
|
idleTimer = setTimeout(() => {
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
}
|
|
2272
|
-
|
|
2469
|
+
idleTimer = void 0;
|
|
2470
|
+
void tryAcquireStartupMutex(lockPath).then(async (token) => {
|
|
2471
|
+
if (token === void 0) {
|
|
2472
|
+
scheduleIdleExit();
|
|
2473
|
+
return;
|
|
2474
|
+
}
|
|
2475
|
+
if (busy() || idleTimer !== void 0) {
|
|
2476
|
+
await releaseStartupMutex(lockPath, token);
|
|
2477
|
+
return;
|
|
2478
|
+
}
|
|
2479
|
+
server.closeAllConnections();
|
|
2480
|
+
for (const client of clients) client.socket.destroy();
|
|
2481
|
+
server.close(() => {
|
|
2482
|
+
void removeOwnLock().then(() => releaseStartupMutex(lockPath, token)).then(() => {
|
|
2483
|
+
process.exit(0);
|
|
2484
|
+
}).catch(() => {
|
|
2485
|
+
process.exit(1);
|
|
2486
|
+
});
|
|
2273
2487
|
});
|
|
2488
|
+
}).catch(() => {
|
|
2489
|
+
process.exit(1);
|
|
2274
2490
|
});
|
|
2275
2491
|
}, TRAJECTORY_IDLE_EXIT_MS);
|
|
2276
2492
|
idleTimer.unref();
|
|
2277
2493
|
};
|
|
2494
|
+
const removeOwnLock = async () => {
|
|
2495
|
+
let current;
|
|
2496
|
+
try {
|
|
2497
|
+
current = JSON.parse(await readFile3(lockPath, "utf8"));
|
|
2498
|
+
} catch (error) {
|
|
2499
|
+
if (isNodeError(error, "ENOENT")) return;
|
|
2500
|
+
throw error;
|
|
2501
|
+
}
|
|
2502
|
+
if (object(current) && current.pid === process.pid && current.startedAt === startedAt) await rm3(lockPath, { force: true });
|
|
2503
|
+
};
|
|
2278
2504
|
const cancelIdleExit = () => {
|
|
2279
2505
|
if (idleTimer !== void 0) {
|
|
2280
2506
|
clearTimeout(idleTimer);
|
|
@@ -2421,7 +2647,7 @@ function createTrajectoryServer(port, lockPath, options = {}) {
|
|
|
2421
2647
|
const runRequest = validId(message.runId) && validId(message.agentId) && message.subagentId === void 0;
|
|
2422
2648
|
const subagentRequest = validId(message.subagentId) && message.runId === void 0 && message.agentId === void 0;
|
|
2423
2649
|
if (!runRequest && !subagentRequest) return;
|
|
2424
|
-
const requestId2 = validId(message.requestId) ? message.requestId :
|
|
2650
|
+
const requestId2 = validId(message.requestId) ? message.requestId : randomUUID3();
|
|
2425
2651
|
const revision = message.revision === void 0 ? void 0 : typeof message.revision === "number" && Number.isSafeInteger(message.revision) && message.revision >= 0 ? message.revision : void 0;
|
|
2426
2652
|
const target2 = publishers.get(message.publisherId);
|
|
2427
2653
|
if (!target2 || !target2.value.connected) {
|
|
@@ -2469,7 +2695,7 @@ function createTrajectoryServer(port, lockPath, options = {}) {
|
|
|
2469
2695
|
return;
|
|
2470
2696
|
}
|
|
2471
2697
|
if (client.kind !== "browser" || message.type !== "ui:action" || typeof message.publisherId !== "string") return;
|
|
2472
|
-
const requestId = typeof message.requestId === "string" && message.requestId.length >= 1 && message.requestId.length <= 200 ? message.requestId :
|
|
2698
|
+
const requestId = typeof message.requestId === "string" && message.requestId.length >= 1 && message.requestId.length <= 200 ? message.requestId : randomUUID3();
|
|
2473
2699
|
if (!isTrajectoryAction(message.action)) {
|
|
2474
2700
|
emit(client, { type: "action-result", requestId, ok: false, error: "Unsupported Trajectory action" });
|
|
2475
2701
|
return;
|
|
@@ -2523,7 +2749,7 @@ function createTrajectoryServer(port, lockPath, options = {}) {
|
|
|
2523
2749
|
return;
|
|
2524
2750
|
}
|
|
2525
2751
|
if (request.method === "GET" && (path2 === "/" || path2 === "/index.html")) {
|
|
2526
|
-
void
|
|
2752
|
+
void readFile3(new URL("./assets/index.html", import.meta.url)).then((html) => {
|
|
2527
2753
|
response.writeHead(200, { "content-type": "text/html; charset=utf-8", "content-length": html.byteLength, "cache-control": "no-store" });
|
|
2528
2754
|
response.end(html);
|
|
2529
2755
|
}).catch(() => {
|
|
@@ -2532,7 +2758,7 @@ function createTrajectoryServer(port, lockPath, options = {}) {
|
|
|
2532
2758
|
return;
|
|
2533
2759
|
}
|
|
2534
2760
|
if (request.method === "GET" && path2 === "/marked.min.js") {
|
|
2535
|
-
void
|
|
2761
|
+
void readFile3(new URL("./assets/marked.min.js", import.meta.url)).then((script) => {
|
|
2536
2762
|
response.writeHead(200, { "content-type": "application/javascript; charset=utf-8", "content-length": script.byteLength, "cache-control": "no-store" });
|
|
2537
2763
|
response.end(script);
|
|
2538
2764
|
}).catch(() => {
|
|
@@ -2541,7 +2767,7 @@ function createTrajectoryServer(port, lockPath, options = {}) {
|
|
|
2541
2767
|
return;
|
|
2542
2768
|
}
|
|
2543
2769
|
if (request.method === "GET" && path2 === "/morphdom.min.js") {
|
|
2544
|
-
void
|
|
2770
|
+
void readFile3(new URL("./assets/morphdom.min.js", import.meta.url)).then((script) => {
|
|
2545
2771
|
response.writeHead(200, { "content-type": "application/javascript; charset=utf-8", "content-length": script.byteLength, "cache-control": "no-store" });
|
|
2546
2772
|
response.end(script);
|
|
2547
2773
|
}).catch(() => {
|
|
@@ -2550,7 +2776,7 @@ function createTrajectoryServer(port, lockPath, options = {}) {
|
|
|
2550
2776
|
return;
|
|
2551
2777
|
}
|
|
2552
2778
|
if (request.method === "GET" && path2 === "/prism.min.js") {
|
|
2553
|
-
void
|
|
2779
|
+
void readFile3(new URL("./assets/prism.min.js", import.meta.url)).then((script) => {
|
|
2554
2780
|
response.writeHead(200, { "content-type": "application/javascript; charset=utf-8", "content-length": script.byteLength, "cache-control": "no-store" });
|
|
2555
2781
|
response.end(script);
|
|
2556
2782
|
}).catch(() => {
|
|
@@ -2559,7 +2785,7 @@ function createTrajectoryServer(port, lockPath, options = {}) {
|
|
|
2559
2785
|
return;
|
|
2560
2786
|
}
|
|
2561
2787
|
if (request.method === "GET" && (path2 === "/favicon.png" || path2 === "/favicon.ico")) {
|
|
2562
|
-
void
|
|
2788
|
+
void readFile3(new URL("./assets/favicon.png", import.meta.url)).then((icon) => {
|
|
2563
2789
|
response.writeHead(200, { "content-type": "image/png", "content-length": icon.byteLength, "cache-control": "no-store" });
|
|
2564
2790
|
response.end(icon);
|
|
2565
2791
|
}).catch(() => {
|
|
@@ -2619,10 +2845,14 @@ Sec-WebSocket-Accept: ${accept}\r
|
|
|
2619
2845
|
});
|
|
2620
2846
|
server.once("listening", () => {
|
|
2621
2847
|
startedAt = Date.now();
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
})
|
|
2848
|
+
try {
|
|
2849
|
+
atomicWriteFile(lockPath, `${JSON.stringify({ pid: process.pid, port, fingerprint: serverFingerprint, startedAt, start: processStart(process.pid) })}
|
|
2850
|
+
`, true);
|
|
2851
|
+
} catch (error) {
|
|
2852
|
+
server.close();
|
|
2853
|
+
server.emit("error", error);
|
|
2854
|
+
return;
|
|
2855
|
+
}
|
|
2626
2856
|
scheduleIdleExit();
|
|
2627
2857
|
});
|
|
2628
2858
|
server.on("close", () => {
|
|
@@ -2634,13 +2864,24 @@ Sec-WebSocket-Accept: ${accept}\r
|
|
|
2634
2864
|
});
|
|
2635
2865
|
return server;
|
|
2636
2866
|
}
|
|
2867
|
+
async function awaitStartupRecord(lockPath, token) {
|
|
2868
|
+
for (let attempt = 0; attempt < 60; attempt += 1) {
|
|
2869
|
+
const holder = readStartupHolder(lockPath, token);
|
|
2870
|
+
if (holder === void 0) break;
|
|
2871
|
+
if (holder.server?.pid === process.pid) return;
|
|
2872
|
+
await new Promise((resolve2) => setTimeout(resolve2, 50));
|
|
2873
|
+
}
|
|
2874
|
+
throw new Error("Trajectory startup was abandoned before the server listened");
|
|
2875
|
+
}
|
|
2637
2876
|
async function main() {
|
|
2638
2877
|
const args = /* @__PURE__ */ new Map();
|
|
2639
2878
|
for (let index = 2; index + 1 < process.argv.length; index += 2) args.set(process.argv[index] ?? "", process.argv[index + 1] ?? "");
|
|
2640
2879
|
const port = Number(args.get("--port"));
|
|
2641
2880
|
const lockPath = args.get("--lock");
|
|
2642
2881
|
const fingerprint = args.get("--fingerprint");
|
|
2882
|
+
const startupToken = args.get("--startup");
|
|
2643
2883
|
if (!Number.isSafeInteger(port) || port < 1 || port > 65535 || !lockPath || !fingerprint) throw new Error("Invalid Trajectory server arguments");
|
|
2884
|
+
if (startupToken !== void 0) await awaitStartupRecord(lockPath, startupToken);
|
|
2644
2885
|
const server = createTrajectoryServer(port, lockPath, { fingerprint });
|
|
2645
2886
|
await new Promise((resolve2, reject) => {
|
|
2646
2887
|
server.once("error", reject);
|