@xingular/harness 1.3.1-unstable.2 → 1.3.1-unstable.3
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 +49 -0
- package/README.md +1 -1
- package/dist/cli.js +1217 -701
- package/dist/sdk/computer/screenshot.d.ts +32 -0
- package/dist/sdk/computer/screenshot.js +35 -0
- package/dist/sdk/context/attribution.d.ts +18 -0
- package/dist/sdk/context/attribution.js +295 -0
- package/dist/sdk/context/types.d.ts +94 -0
- package/dist/sdk/context/types.js +10 -0
- package/dist/sdk/index.d.ts +2 -1
- package/dist/sdk/index.js +2 -1
- package/dist/sdk/plugins/builtin.js +1 -0
- package/dist/sdk/prompt/compile.d.ts +42 -2
- package/dist/sdk/prompt/compile.js +87 -15
- package/dist/sdk/server/methods.js +3 -0
- package/dist/sdk/sessions/contracts.d.ts +4 -0
- package/dist/sdk/sessions/contracts.js +2 -0
- package/dist/sdk/sessions/runner.d.ts +10 -0
- package/dist/sdk/sessions/runner.js +17 -0
- package/dist/sdk/sessions/subagentService.d.ts +11 -1
- package/dist/sdk/sessions/subagentService.js +120 -38
- package/dist/sdk/sessions/subagents.d.ts +31 -0
- package/dist/sdk/sessions/subagents.js +45 -0
- package/dist/sdk/terminal/client.d.ts +1 -1
- package/dist/sdk/terminal/client.js +13 -6
- package/dist/sdk/terminal/control.d.ts +1 -1
- package/dist/sdk/terminal/control.js +2 -2
- package/dist/sdk/terminal/controller.d.ts +9 -0
- package/dist/sdk/terminal/controller.js +48 -11
- package/dist/sdk/terminal/piExtension.js +35 -1
- package/dist/sdk/terminal/terminals.d.ts +2 -0
- package/dist/sdk/terminal/terminals.js +11 -0
- package/dist/sdk/terminal/tui/commands.d.ts +1 -2
- package/dist/sdk/terminal/tui/commands.js +1 -4
- package/dist/sdk/terminal/tui/dialogs.d.ts +3 -2
- package/dist/sdk/terminal/tui/dialogs.js +4 -3
- package/dist/sdk/terminal/tui/keybindings.d.ts +1 -1
- package/dist/sdk/terminal/tui/keybindings.js +1 -1
- package/dist/sdk/terminal/tui/modeChoices.d.ts +3 -2
- package/dist/sdk/terminal/tui/modeChoices.js +4 -4
- package/dist/sdk/terminal/tui/mouseReport.d.ts +30 -0
- package/dist/sdk/terminal/tui/mouseReport.js +80 -0
- package/dist/sdk/terminal/tui/pages/annotatePage.js +3 -2
- package/dist/sdk/terminal/tui/pages/browserPage.d.ts +1 -1
- package/dist/sdk/terminal/tui/pages/contextPage.d.ts +54 -0
- package/dist/sdk/terminal/tui/pages/contextPage.js +393 -0
- package/dist/sdk/terminal/tui/pages/trajectoryPage.js +5 -4
- package/dist/sdk/terminal/tui/runtime.js +8 -2
- package/dist/sdk/terminal/tui/search.js +3 -2
- package/dist/sdk/terminal/tui/skillInvocation.d.ts +21 -2
- package/dist/sdk/terminal/tui/skillInvocation.js +31 -11
- package/dist/sdk/tools/defaultSkills.d.ts +19 -0
- package/dist/sdk/tools/defaultSkills.js +27 -1
- package/dist/sdk/tools/dispatch.js +8 -9
- package/dist/sdk/tools/spawnSubagent.d.ts +1 -1
- package/dist/sdk/tools/spawnSubagent.js +4 -2
- package/dist/terminal-opentui.js +570 -240
- package/dist/terminal-pi.js +142 -28
- package/docs/README.md +1 -0
- package/docs/architecture/02-sessions-and-runs.md +9 -0
- package/docs/architecture/04-prompt.md +13 -4
- package/docs/architecture/07-tools-and-gate.md +1 -1
- package/docs/architecture/11-terminal.md +12 -2
- package/docs/architecture/13-world-tools.md +17 -3
- package/docs/architecture/14-surfaces-and-parity.md +3 -3
- package/docs/architecture/README.md +1 -0
- package/docs/architecture/proposals/PROP-0049-context-attribution.md +382 -0
- package/docs/architecture/proposals/README.md +1 -0
- package/docs/decisions/ADR-0048-required-skills-from-a-message.md +42 -0
- package/docs/decisions/ADR-0050-approved-window-screenshots.md +19 -0
- package/docs/decisions/ADR-0051-terminal-decision-wait.md +10 -0
- package/docs/decisions/ADR-0052-per-profile-subagent-budgets.md +25 -0
- package/docs/parity.md +6 -6
- package/docs/releases/1.3.1-unstable.3.md +54 -0
- package/docs/terminal-tui.md +28 -15
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -145,15 +145,15 @@ __export(setup_exports, {
|
|
|
145
145
|
});
|
|
146
146
|
import { spawn as spawn3 } from "node:child_process";
|
|
147
147
|
import { createHash as createHash12 } from "node:crypto";
|
|
148
|
-
import { chmodSync as chmodSync9, closeSync as closeSync4, existsSync as existsSync25, mkdirSync as mkdirSync20, openSync as openSync4, readFileSync as
|
|
149
|
-
import { dirname as dirname17, join as
|
|
148
|
+
import { chmodSync as chmodSync9, closeSync as closeSync4, existsSync as existsSync25, mkdirSync as mkdirSync20, openSync as openSync4, readFileSync as readFileSync27, statSync as statSync17 } from "node:fs";
|
|
149
|
+
import { dirname as dirname17, join as join55 } from "node:path";
|
|
150
150
|
function scriptHash(text10) {
|
|
151
151
|
return createHash12("sha256").update(text10).digest("hex");
|
|
152
152
|
}
|
|
153
153
|
function setupScript(checkout) {
|
|
154
|
-
const path4 =
|
|
155
|
-
if (!existsSync25(path4) || !
|
|
156
|
-
return { path: path4, hash: scriptHash(
|
|
154
|
+
const path4 = join55(checkout, SETUP_SCRIPT);
|
|
155
|
+
if (!existsSync25(path4) || !statSync17(path4).isFile()) return null;
|
|
156
|
+
return { path: path4, hash: scriptHash(readFileSync27(path4)) };
|
|
157
157
|
}
|
|
158
158
|
function runSetup(input) {
|
|
159
159
|
const script = setupScript(input.checkout);
|
|
@@ -214,7 +214,7 @@ import { resolve as resolve18 } from "node:path";
|
|
|
214
214
|
// package.json
|
|
215
215
|
var package_default = {
|
|
216
216
|
name: "@xingular/harness",
|
|
217
|
-
version: "1.3.1-unstable.
|
|
217
|
+
version: "1.3.1-unstable.3",
|
|
218
218
|
type: "module",
|
|
219
219
|
description: "Xingular Harness \u2014 a Pi agent harness built on recursive harnessing (Harness\xB2): versioned eight-component variants, refinement from evidence, multi-account sessions, a compiled prompt, project notes, tools, and MCP",
|
|
220
220
|
repository: {
|
|
@@ -363,7 +363,7 @@ function log(...parts) {
|
|
|
363
363
|
|
|
364
364
|
// src/sessions/subagentService.ts
|
|
365
365
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
366
|
-
import { join as
|
|
366
|
+
import { join as join15 } from "node:path";
|
|
367
367
|
|
|
368
368
|
// src/capabilities/runSnapshot.ts
|
|
369
369
|
init_errors();
|
|
@@ -486,6 +486,8 @@ var contextSnapshotPayload = z.object({
|
|
|
486
486
|
systemPrompt: z.string().max(1e5),
|
|
487
487
|
contextUpdate: z.string().max(1e5).optional(),
|
|
488
488
|
tools: z.array(z.object({ name: z.string(), description: z.string().max(2e3), parameters: z.unknown() })).max(120),
|
|
489
|
+
/** The headroom Pi held the run to when it measured compaction, as the session's own settings give it. */
|
|
490
|
+
compaction: z.object({ enabled: z.boolean(), reserveTokens: z.number().nonnegative() }).optional(),
|
|
489
491
|
systemPromptTruncated: z.boolean().optional(),
|
|
490
492
|
contextUpdateTruncated: z.boolean().optional(),
|
|
491
493
|
toolsTruncated: z.boolean().optional()
|
|
@@ -960,6 +962,16 @@ function parse(text10) {
|
|
|
960
962
|
return null;
|
|
961
963
|
}
|
|
962
964
|
}
|
|
965
|
+
function bodyOf(text10) {
|
|
966
|
+
const parts = split(text10);
|
|
967
|
+
if (!parts) return text10;
|
|
968
|
+
try {
|
|
969
|
+
parseYaml(parts.yaml);
|
|
970
|
+
return parts.body;
|
|
971
|
+
} catch {
|
|
972
|
+
return text10;
|
|
973
|
+
}
|
|
974
|
+
}
|
|
963
975
|
function serialize(front, body2) {
|
|
964
976
|
let yaml;
|
|
965
977
|
try {
|
|
@@ -1819,10 +1831,10 @@ function todoTool(run2) {
|
|
|
1819
1831
|
// src/tools/checkpoint.ts
|
|
1820
1832
|
var CHECKPOINT_WRITE = "checkpoint_write";
|
|
1821
1833
|
var text2 = (value) => typeof value === "string" ? value.trim() : "";
|
|
1822
|
-
function collect(value, parse4,
|
|
1834
|
+
function collect(value, parse4, limit2) {
|
|
1823
1835
|
if (!Array.isArray(value)) return [];
|
|
1824
1836
|
const out = [];
|
|
1825
|
-
for (const entry2 of value.slice(0,
|
|
1837
|
+
for (const entry2 of value.slice(0, limit2)) {
|
|
1826
1838
|
const parsed = parse4(entry2);
|
|
1827
1839
|
if (parsed) out.push(parsed);
|
|
1828
1840
|
}
|
|
@@ -1949,12 +1961,12 @@ function checkpointTool(run2, slice) {
|
|
|
1949
1961
|
|
|
1950
1962
|
// src/sessions/history.ts
|
|
1951
1963
|
init_errors();
|
|
1952
|
-
import { readdirSync as
|
|
1953
|
-
import { isAbsolute as isAbsolute2, join as
|
|
1964
|
+
import { readdirSync as readdirSync8, readFileSync as readFileSync9, realpathSync } from "node:fs";
|
|
1965
|
+
import { isAbsolute as isAbsolute2, join as join11, relative as relative3 } from "node:path";
|
|
1954
1966
|
|
|
1955
1967
|
// src/prompt/compile.ts
|
|
1956
|
-
import { readdirSync as
|
|
1957
|
-
import { join as
|
|
1968
|
+
import { readdirSync as readdirSync7, readFileSync as readFileSync8, statSync as statSync6 } from "node:fs";
|
|
1969
|
+
import { join as join10 } from "node:path";
|
|
1958
1970
|
|
|
1959
1971
|
// src/core/projects.ts
|
|
1960
1972
|
init_errors();
|
|
@@ -2027,9 +2039,45 @@ function projectOf(root, context) {
|
|
|
2027
2039
|
// src/prompt/compile.ts
|
|
2028
2040
|
init_fs();
|
|
2029
2041
|
|
|
2042
|
+
// src/tools/defaultSkills.ts
|
|
2043
|
+
import { existsSync as existsSync6, readdirSync as readdirSync5, readFileSync as readFileSync6, statSync as statSync4 } from "node:fs";
|
|
2044
|
+
import { dirname as dirname4, join as join8 } from "node:path";
|
|
2045
|
+
import { fileURLToPath } from "node:url";
|
|
2046
|
+
var SKILL_NAME = /^[a-z0-9][a-z0-9_-]*$/;
|
|
2047
|
+
function defaultSkillPath() {
|
|
2048
|
+
let dir2 = dirname4(fileURLToPath(import.meta.url));
|
|
2049
|
+
for (; ; ) {
|
|
2050
|
+
const path4 = join8(dir2, "builtin", "skills", "plugin-authoring", "SKILL.md");
|
|
2051
|
+
if (existsSync6(path4)) return path4;
|
|
2052
|
+
const parent = dirname4(dir2);
|
|
2053
|
+
if (parent === dir2) throw new Error("The bundled plugin-authoring skill is missing.");
|
|
2054
|
+
dir2 = parent;
|
|
2055
|
+
}
|
|
2056
|
+
}
|
|
2057
|
+
function defaultSkillPaths(variantDir) {
|
|
2058
|
+
return variantDir && existsSync6(join8(variantDir, "skills", "plugin-authoring", "SKILL.md")) ? [] : [defaultSkillPath()];
|
|
2059
|
+
}
|
|
2060
|
+
function readSkillFile(variantDir, name) {
|
|
2061
|
+
const wanted = name.trim().replace(/^skills\//, "").replace(/`/g, "");
|
|
2062
|
+
if (!SKILL_NAME.test(wanted)) return null;
|
|
2063
|
+
const variant = variantDir ? join8(variantDir, "skills", wanted, "SKILL.md") : null;
|
|
2064
|
+
const builtin = wanted === "plugin-authoring" && defaultSkillPaths(variantDir).length ? defaultSkillPath() : null;
|
|
2065
|
+
const path4 = variant && existsSync6(variant) && statSync4(variant).isFile() ? variant : builtin;
|
|
2066
|
+
if (!path4) return null;
|
|
2067
|
+
const baseDir = dirname4(path4);
|
|
2068
|
+
const scripts = join8(baseDir, "scripts");
|
|
2069
|
+
return {
|
|
2070
|
+
name: wanted,
|
|
2071
|
+
path: path4,
|
|
2072
|
+
baseDir,
|
|
2073
|
+
body: bodyOf(readFileSync6(path4, "utf8")),
|
|
2074
|
+
helpers: existsSync6(scripts) ? readdirSync5(scripts) : []
|
|
2075
|
+
};
|
|
2076
|
+
}
|
|
2077
|
+
|
|
2030
2078
|
// src/wiki/notes.ts
|
|
2031
|
-
import { existsSync as
|
|
2032
|
-
import { dirname as
|
|
2079
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync4, readdirSync as readdirSync6, readFileSync as readFileSync7, renameSync as renameSync2, rmSync as rmSync4, statSync as statSync5 } from "node:fs";
|
|
2080
|
+
import { dirname as dirname5, join as join9, relative as relative2, sep as sep3 } from "node:path";
|
|
2033
2081
|
|
|
2034
2082
|
// src/core/changes.ts
|
|
2035
2083
|
var listeners = /* @__PURE__ */ new Set();
|
|
@@ -2060,10 +2108,10 @@ function looksSecret(text10) {
|
|
|
2060
2108
|
var LEGACY_FOLDERS = ["blocks", "facts", "raw", "revisions", "inbox", "operations", "trash"];
|
|
2061
2109
|
var MAX_NOTE = 4e5;
|
|
2062
2110
|
function wikiDir(root) {
|
|
2063
|
-
return
|
|
2111
|
+
return join9(root, "wiki");
|
|
2064
2112
|
}
|
|
2065
2113
|
function historyDir(root) {
|
|
2066
|
-
return
|
|
2114
|
+
return join9(root, "wiki-history");
|
|
2067
2115
|
}
|
|
2068
2116
|
function cleanPath(path4) {
|
|
2069
2117
|
const clean2 = String(path4 ?? "").trim().replace(/\\/g, "/").replace(/^\/+|\/+$/g, "").replace(/\.md$/i, "");
|
|
@@ -2076,7 +2124,7 @@ function cleanPath(path4) {
|
|
|
2076
2124
|
return clean2;
|
|
2077
2125
|
}
|
|
2078
2126
|
function fileOf(root, path4) {
|
|
2079
|
-
return
|
|
2127
|
+
return join9(wikiDir(root), `${cleanPath(path4)}.md`);
|
|
2080
2128
|
}
|
|
2081
2129
|
function projectOfPath(path4) {
|
|
2082
2130
|
const parts = path4.split("/");
|
|
@@ -2100,16 +2148,16 @@ function safeParse(text10) {
|
|
|
2100
2148
|
function walk2(dir2, into) {
|
|
2101
2149
|
let names2;
|
|
2102
2150
|
try {
|
|
2103
|
-
names2 =
|
|
2151
|
+
names2 = readdirSync6(dir2);
|
|
2104
2152
|
} catch {
|
|
2105
2153
|
return;
|
|
2106
2154
|
}
|
|
2107
2155
|
for (const name of names2.sort()) {
|
|
2108
2156
|
if (name.startsWith(".")) continue;
|
|
2109
|
-
const path4 =
|
|
2157
|
+
const path4 = join9(dir2, name);
|
|
2110
2158
|
let isDir2 = false;
|
|
2111
2159
|
try {
|
|
2112
|
-
isDir2 =
|
|
2160
|
+
isDir2 = statSync5(path4).isDirectory();
|
|
2113
2161
|
} catch {
|
|
2114
2162
|
continue;
|
|
2115
2163
|
}
|
|
@@ -2120,15 +2168,15 @@ function walk2(dir2, into) {
|
|
|
2120
2168
|
function paths(root) {
|
|
2121
2169
|
const wiki2 = wikiDir(root);
|
|
2122
2170
|
const files3 = [];
|
|
2123
|
-
if (
|
|
2124
|
-
walk2(
|
|
2125
|
-
walk2(
|
|
2171
|
+
if (existsSync7(join9(wiki2, "home.md"))) files3.push(join9(wiki2, "home.md"));
|
|
2172
|
+
walk2(join9(wiki2, "library"), files3);
|
|
2173
|
+
walk2(join9(wiki2, "projects"), files3);
|
|
2126
2174
|
return files3.map((file2) => relative2(wiki2, file2).split(sep3).join("/").replace(/\.md$/, ""));
|
|
2127
2175
|
}
|
|
2128
2176
|
function summary(root, path4) {
|
|
2129
2177
|
const file2 = fileOf(root, path4);
|
|
2130
|
-
const text10 =
|
|
2131
|
-
return { path: path4, title: titleOf(path4, text10), project: projectOfPath(path4), updatedAt:
|
|
2178
|
+
const text10 = readFileSync7(file2, "utf8");
|
|
2179
|
+
return { path: path4, title: titleOf(path4, text10), project: projectOfPath(path4), updatedAt: statSync5(file2).mtime.toISOString(), size: text10.length };
|
|
2132
2180
|
}
|
|
2133
2181
|
function list(root, options2 = {}) {
|
|
2134
2182
|
return paths(root).filter((path4) => options2.project === void 0 || projectOfPath(path4) === options2.project).map((path4) => summary(root, path4));
|
|
@@ -2172,7 +2220,7 @@ function graph(root) {
|
|
|
2172
2220
|
const titles = new Map(nodes.map((node) => [node.title.toLowerCase(), node.path]));
|
|
2173
2221
|
const edges = [];
|
|
2174
2222
|
for (const node of nodes) {
|
|
2175
|
-
const body2 =
|
|
2223
|
+
const body2 = readFileSync7(fileOf(root, node.path), "utf8");
|
|
2176
2224
|
for (const to of linksIn(body2, node.path, known, titles)) edges.push({ from: node.path, to });
|
|
2177
2225
|
}
|
|
2178
2226
|
return { nodes, edges };
|
|
@@ -2180,8 +2228,8 @@ function graph(root) {
|
|
|
2180
2228
|
function read(root, path4) {
|
|
2181
2229
|
const clean2 = cleanPath(path4);
|
|
2182
2230
|
const file2 = fileOf(root, clean2);
|
|
2183
|
-
if (!
|
|
2184
|
-
const text10 =
|
|
2231
|
+
if (!existsSync7(file2)) throw notFound(`The note ${clean2}`);
|
|
2232
|
+
const text10 = readFileSync7(file2, "utf8");
|
|
2185
2233
|
const { nodes, edges } = graph(root);
|
|
2186
2234
|
const known = new Set(nodes.map((node) => node.path));
|
|
2187
2235
|
const titles = new Map(nodes.map((node) => [node.title.toLowerCase(), node.path]));
|
|
@@ -2200,14 +2248,14 @@ function write(root, path4, body2, options2 = {}) {
|
|
|
2200
2248
|
const project = projectOfPath(clean2);
|
|
2201
2249
|
if (project && !projectsOrNone(root).some((known) => known.slug === project)) throw invalid(`There is no project with the slug ${project}.`);
|
|
2202
2250
|
const file2 = fileOf(root, clean2);
|
|
2203
|
-
if (
|
|
2204
|
-
const current2 =
|
|
2251
|
+
if (existsSync7(file2)) {
|
|
2252
|
+
const current2 = statSync5(file2).mtime.toISOString();
|
|
2205
2253
|
if (options2.expectedUpdatedAt && options2.expectedUpdatedAt !== current2) throw new HarnessError("conflict", "The note changed since it was opened. Reload it and try again.");
|
|
2206
|
-
const previous =
|
|
2254
|
+
const previous = readFileSync7(file2, "utf8");
|
|
2207
2255
|
if (previous === body2) return read(root, clean2);
|
|
2208
|
-
atomicWrite(
|
|
2256
|
+
atomicWrite(join9(historyDir(root), clean2, `${now().replace(/[:.]/g, "-")}.md`), previous);
|
|
2209
2257
|
}
|
|
2210
|
-
mkdirSync4(
|
|
2258
|
+
mkdirSync4(dirname5(file2), { recursive: true });
|
|
2211
2259
|
atomicWrite(file2, body2);
|
|
2212
2260
|
noteChange({ wiki: wikiDir(root), id: clean2, path: file2, text: body2, actor: options2.actor ?? "user", reason: options2.reason ?? "Saved" });
|
|
2213
2261
|
return read(root, clean2);
|
|
@@ -2215,30 +2263,30 @@ function write(root, path4, body2, options2 = {}) {
|
|
|
2215
2263
|
function remove(root, path4) {
|
|
2216
2264
|
const clean2 = cleanPath(path4);
|
|
2217
2265
|
const file2 = fileOf(root, clean2);
|
|
2218
|
-
if (!
|
|
2219
|
-
atomicWrite(
|
|
2266
|
+
if (!existsSync7(file2)) throw notFound(`The note ${clean2}`);
|
|
2267
|
+
atomicWrite(join9(historyDir(root), clean2, `${now().replace(/[:.]/g, "-")}.md`), readFileSync7(file2, "utf8"));
|
|
2220
2268
|
rmSync4(file2);
|
|
2221
2269
|
}
|
|
2222
2270
|
function versions(root, path4) {
|
|
2223
|
-
const dir2 =
|
|
2271
|
+
const dir2 = join9(historyDir(root), cleanPath(path4));
|
|
2224
2272
|
try {
|
|
2225
|
-
return
|
|
2273
|
+
return readdirSync6(dir2).filter((name) => name.endsWith(".md")).sort().reverse().map((name) => ({ id: name.replace(/\.md$/, ""), savedAt: statSync5(join9(dir2, name)).mtime.toISOString() }));
|
|
2226
2274
|
} catch {
|
|
2227
2275
|
return [];
|
|
2228
2276
|
}
|
|
2229
2277
|
}
|
|
2230
2278
|
function version(root, path4, id) {
|
|
2231
2279
|
if (!/^[0-9A-Za-z-]+$/.test(id)) throw invalid("Invalid version.");
|
|
2232
|
-
const file2 =
|
|
2233
|
-
if (!
|
|
2234
|
-
return
|
|
2280
|
+
const file2 = join9(historyDir(root), cleanPath(path4), `${id}.md`);
|
|
2281
|
+
if (!existsSync7(file2)) throw notFound("That version");
|
|
2282
|
+
return readFileSync7(file2, "utf8");
|
|
2235
2283
|
}
|
|
2236
2284
|
function search(root, query, options2 = {}) {
|
|
2237
2285
|
const words = [...new Set(String(query ?? "").toLowerCase().split(/[^\p{L}\p{N}]+/u).filter((word) => word.length > 1))].slice(0, 16);
|
|
2238
2286
|
if (!words.length) return [];
|
|
2239
2287
|
const hits = [];
|
|
2240
2288
|
for (const path4 of paths(root)) {
|
|
2241
|
-
const text10 =
|
|
2289
|
+
const text10 = readFileSync7(fileOf(root, path4), "utf8");
|
|
2242
2290
|
const lower = text10.toLowerCase();
|
|
2243
2291
|
const title2 = titleOf(path4, text10);
|
|
2244
2292
|
let score = 0;
|
|
@@ -2264,22 +2312,22 @@ function search(root, query, options2 = {}) {
|
|
|
2264
2312
|
}
|
|
2265
2313
|
function ensureLayout(root, productName) {
|
|
2266
2314
|
const wiki2 = wikiDir(root);
|
|
2267
|
-
mkdirSync4(
|
|
2268
|
-
mkdirSync4(
|
|
2269
|
-
if (!
|
|
2315
|
+
mkdirSync4(join9(wiki2, "library"), { recursive: true });
|
|
2316
|
+
mkdirSync4(join9(wiki2, "projects"), { recursive: true });
|
|
2317
|
+
if (!existsSync7(join9(wiki2, "home.md"))) atomicWrite(join9(wiki2, "home.md"), `# Home
|
|
2270
2318
|
|
|
2271
2319
|
Notes about your projects for ${productName}. Link notes with [[library/name]] or [[projects/<slug>/name]].
|
|
2272
2320
|
`);
|
|
2273
|
-
for (const project of projectsOrNone(root)) mkdirSync4(
|
|
2321
|
+
for (const project of projectsOrNone(root)) mkdirSync4(join9(wiki2, "projects", project.slug), { recursive: true });
|
|
2274
2322
|
}
|
|
2275
2323
|
function moveLegacy(root) {
|
|
2276
2324
|
const wiki2 = wikiDir(root);
|
|
2277
|
-
const found = LEGACY_FOLDERS.filter((name) =>
|
|
2278
|
-
const loose = ["index.md", "log.md", "schema.md"].filter((name) =>
|
|
2325
|
+
const found = LEGACY_FOLDERS.filter((name) => existsSync7(join9(wiki2, name)));
|
|
2326
|
+
const loose = ["index.md", "log.md", "schema.md"].filter((name) => existsSync7(join9(wiki2, name)));
|
|
2279
2327
|
if (!found.length && !loose.length) return null;
|
|
2280
|
-
const dest =
|
|
2328
|
+
const dest = join9(root, "legacy", `wiki-${now().replace(/[:.]/g, "-")}`);
|
|
2281
2329
|
mkdirSync4(dest, { recursive: true });
|
|
2282
|
-
for (const name of [...found, ...loose]) renameSync2(
|
|
2330
|
+
for (const name of [...found, ...loose]) renameSync2(join9(wiki2, name), join9(dest, name));
|
|
2283
2331
|
return dest;
|
|
2284
2332
|
}
|
|
2285
2333
|
|
|
@@ -2379,10 +2427,12 @@ var WIKI_BUDGET = 2500;
|
|
|
2379
2427
|
var TOOLS_BUDGET = 8e3;
|
|
2380
2428
|
var REPORTING_BUDGET = 2e3;
|
|
2381
2429
|
var SESSION_STATE_BUDGET = 1e3;
|
|
2430
|
+
var REQUIRED_SKILLS_BUDGET = 12e3;
|
|
2431
|
+
var REQUIRED_SKILLS_POINTER = "Some required skill text was omitted to fit. Load the rest with skill_load.";
|
|
2382
2432
|
var REFERENCES_BUDGET = 12e3;
|
|
2383
2433
|
var VARIANT_BUDGET = 3e4;
|
|
2384
2434
|
var NOTES_LISTED = 25;
|
|
2385
|
-
var SECTION_ORDER = { harnessIdentity: 5, system: 25, sessionState: 30, guardrails: 40, memory: 45, references: 50, subagents: 64, scripts: 66, wiki: 80, tools: 90, reporting: 95 };
|
|
2435
|
+
var SECTION_ORDER = { harnessIdentity: 5, system: 25, sessionState: 30, guardrails: 40, memory: 45, references: 50, requiredSkills: 52, subagents: 64, scripts: 66, wiki: 80, tools: 90, reporting: 95 };
|
|
2386
2436
|
var REPORTING_GUIDANCE = `When you finish work, write the final reply for a person who did not watch you work.
|
|
2387
2437
|
|
|
2388
2438
|
- Start with the answer or outcome in one or two sentences. If they asked a question, answer it first.
|
|
@@ -2418,8 +2468,8 @@ function section(id, title2, text10, budget, pointer, sources) {
|
|
|
2418
2468
|
const { body: body2, cut } = fit(text10, budget, pointer);
|
|
2419
2469
|
return { id, title: title2, body: body2, sources, budget, size: charCount(body2), cut };
|
|
2420
2470
|
}
|
|
2421
|
-
function clip(text10,
|
|
2422
|
-
return charCount(text10) <=
|
|
2471
|
+
function clip(text10, limit2) {
|
|
2472
|
+
return charCount(text10) <= limit2 ? text10 : `${takeChars(text10, limit2)}\u2026`;
|
|
2423
2473
|
}
|
|
2424
2474
|
function renderCompactionCheckpoint(input) {
|
|
2425
2475
|
if (!input.todo.length && !input.planInstructions) return null;
|
|
@@ -2588,6 +2638,45 @@ ${fitted.body}
|
|
|
2588
2638
|
if (built) built.cut ||= cut;
|
|
2589
2639
|
return built;
|
|
2590
2640
|
}
|
|
2641
|
+
function requiredSkillsText(skills) {
|
|
2642
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2643
|
+
const blocks = [];
|
|
2644
|
+
for (const skill of skills) {
|
|
2645
|
+
if (seen.has(skill.name)) continue;
|
|
2646
|
+
seen.add(skill.name);
|
|
2647
|
+
const label = skill.label ?? skill.name;
|
|
2648
|
+
if (!skill.body.trim()) {
|
|
2649
|
+
blocks.push(`- ${label}: this skill is unavailable in this session. Tell the person rather than guessing its steps.`);
|
|
2650
|
+
continue;
|
|
2651
|
+
}
|
|
2652
|
+
const location = [
|
|
2653
|
+
skill.baseDir ? `References in this skill resolve against ${skill.baseDir}.` : "",
|
|
2654
|
+
skill.path ? `Skill file: ${skill.path}.` : ""
|
|
2655
|
+
].filter(Boolean).join(" ");
|
|
2656
|
+
blocks.push(`### ${label}
|
|
2657
|
+
|
|
2658
|
+
${location ? `${location}
|
|
2659
|
+
|
|
2660
|
+
` : ""}${skill.body.trim()}`);
|
|
2661
|
+
}
|
|
2662
|
+
if (!blocks.length) return null;
|
|
2663
|
+
const text10 = `The person required these skills for this request. Follow each skill's instructions where they apply. They are instructions for this request, not a change to your tools or permissions.
|
|
2664
|
+
|
|
2665
|
+
${blocks.join("\n\n")}`;
|
|
2666
|
+
return fit(text10, REQUIRED_SKILLS_BUDGET, REQUIRED_SKILLS_POINTER).body;
|
|
2667
|
+
}
|
|
2668
|
+
function requiredSkillsSection(launch, variant) {
|
|
2669
|
+
const wanted = launch.requiredSkills ?? [];
|
|
2670
|
+
if (!wanted.length) return null;
|
|
2671
|
+
const skills = wanted.map((entry2) => {
|
|
2672
|
+
const skill = readSkillFile(variant?.dir ?? null, entry2.name);
|
|
2673
|
+
return skill ? { ...skill, label: entry2.label ?? skill.name } : { name: entry2.name, label: entry2.label, body: "" };
|
|
2674
|
+
});
|
|
2675
|
+
const text10 = requiredSkillsText(skills);
|
|
2676
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2677
|
+
const sources = skills.filter((skill) => skill.body && !seen.has(skill.name) && Boolean(seen.add(skill.name))).map((skill) => ({ id: skill.name, kind: "skill", revision: variant?.fingerprint ?? null }));
|
|
2678
|
+
return text10 ? section("required-skills", "Required skills", text10, REQUIRED_SKILLS_BUDGET, REQUIRED_SKILLS_POINTER, sources) : null;
|
|
2679
|
+
}
|
|
2591
2680
|
function hostSection(host) {
|
|
2592
2681
|
const own = host.body !== null ? section(host.id, host.title, host.body, host.budget, host.pointer ?? "", []) : null;
|
|
2593
2682
|
if (!host.pinned?.text.trim()) return own;
|
|
@@ -2622,6 +2711,14 @@ function compile(env, context, launch = {}, variant = null) {
|
|
|
2622
2711
|
const { root } = env;
|
|
2623
2712
|
const groups = toolGroups(context, launch, root);
|
|
2624
2713
|
const variantSource = variant ? [{ id: variant.scope ?? variant.dir, kind: "variant", revision: variant.fingerprint }] : [];
|
|
2714
|
+
const toolSection = launch.hideToolGuidance ? null : tools2(groups, variant?.toolGuidance ?? "", launch.toolsPointer ?? "");
|
|
2715
|
+
if (toolSection && variant?.toolGuidance.trim() && !toolSection.cut) {
|
|
2716
|
+
const block = `### How to use your tools
|
|
2717
|
+
|
|
2718
|
+
${variant.toolGuidance.trim()}
|
|
2719
|
+
`;
|
|
2720
|
+
toolSection.sources = [{ ...variantSource[0], chars: Math.min(block.length, toolSection.size) }];
|
|
2721
|
+
}
|
|
2625
2722
|
const built = [
|
|
2626
2723
|
{
|
|
2627
2724
|
order: SECTION_ORDER.harnessIdentity,
|
|
@@ -2630,8 +2727,9 @@ function compile(env, context, launch = {}, variant = null) {
|
|
|
2630
2727
|
...(variant?.sections ?? []).map((entry2) => ({ order: entry2.order, section: section(entry2.id, entry2.title, entry2.body, VARIANT_BUDGET, "", variantSource) })),
|
|
2631
2728
|
{ order: SECTION_ORDER.sessionState, section: sessionStateSection(launch.sessionState, launch.tools ?? []) },
|
|
2632
2729
|
{ order: SECTION_ORDER.references, section: selectedReferences(root, launch) },
|
|
2730
|
+
{ order: SECTION_ORDER.requiredSkills, section: requiredSkillsSection(launch, variant) },
|
|
2633
2731
|
{ order: SECTION_ORDER.wiki, section: wiki(root, context) },
|
|
2634
|
-
{ order: SECTION_ORDER.tools, section:
|
|
2732
|
+
{ order: SECTION_ORDER.tools, section: toolSection },
|
|
2635
2733
|
{ order: SECTION_ORDER.reporting, section: section("reporting", "Reporting your work", REPORTING_GUIDANCE, REPORTING_BUDGET, "", []) },
|
|
2636
2734
|
...(launch.standard ? standardSections({ ...launch.standard, project: launch.standard.project ?? projectName(root, context) }, launch.tools ?? []).filter((own) => !(launch.sections ?? []).some((host) => host.id === own.id)) : []).map((own) => ({ order: own.order, section: hostSection(own) })),
|
|
2637
2735
|
...(launch.sections ?? []).filter((host) => host.id !== "session-state").map((host) => ({ order: host.order, section: hostSection(host) }))
|
|
@@ -2647,23 +2745,29 @@ function compile(env, context, launch = {}, variant = null) {
|
|
|
2647
2745
|
compiledAt: now()
|
|
2648
2746
|
};
|
|
2649
2747
|
}
|
|
2650
|
-
function
|
|
2748
|
+
function renderSized(env, pack) {
|
|
2651
2749
|
let text10 = `# ${env.productName} context
|
|
2652
2750
|
`;
|
|
2751
|
+
const sizes = {};
|
|
2653
2752
|
for (const entry2 of pack.sections) {
|
|
2654
|
-
|
|
2753
|
+
const piece = entry2.id === "identity" ? `
|
|
2655
2754
|
${entry2.body}
|
|
2656
|
-
|
|
2657
|
-
else text10 += `
|
|
2755
|
+
` : `
|
|
2658
2756
|
## ${entry2.title}
|
|
2659
2757
|
|
|
2660
2758
|
${entry2.body}
|
|
2661
2759
|
`;
|
|
2760
|
+
sizes[entry2.id] = (sizes[entry2.id] ?? 0) + piece.length;
|
|
2761
|
+
text10 += piece;
|
|
2662
2762
|
}
|
|
2663
|
-
|
|
2763
|
+
const total = Object.values(sizes).reduce((sum, size2) => sum + size2, 0);
|
|
2764
|
+
return { text: text10, sizes, framing: text10.length - total };
|
|
2765
|
+
}
|
|
2766
|
+
function render(env, pack) {
|
|
2767
|
+
return renderSized(env, pack).text;
|
|
2664
2768
|
}
|
|
2665
2769
|
function packPath(root, runId) {
|
|
2666
|
-
return
|
|
2770
|
+
return join10(root, "runs", safeId(runId), "context.json");
|
|
2667
2771
|
}
|
|
2668
2772
|
function load2(root, runId) {
|
|
2669
2773
|
return readJson(packPath(root, runId));
|
|
@@ -2671,22 +2775,23 @@ function load2(root, runId) {
|
|
|
2671
2775
|
function record(root, pack) {
|
|
2672
2776
|
if (!pack.runId) return;
|
|
2673
2777
|
try {
|
|
2674
|
-
if (isDir(
|
|
2778
|
+
if (isDir(join10(root, "runs", safeId(pack.runId)))) writeJson(packPath(root, pack.runId), pack);
|
|
2675
2779
|
} catch {
|
|
2676
2780
|
}
|
|
2677
2781
|
}
|
|
2678
2782
|
var BUILT_IN_DYNAMIC = [
|
|
2679
2783
|
{ id: "session-state", order: SECTION_ORDER.sessionState },
|
|
2680
2784
|
{ id: "references", order: SECTION_ORDER.references },
|
|
2785
|
+
{ id: "required-skills", order: SECTION_ORDER.requiredSkills },
|
|
2681
2786
|
{ id: "wiki", order: SECTION_ORDER.wiki }
|
|
2682
2787
|
];
|
|
2683
|
-
var CONTEXT_GUIDANCE = "App-origin context updates in the conversation supply current Wiki notes, active work, session state, and
|
|
2788
|
+
var CONTEXT_GUIDANCE = "App-origin context updates in the conversation supply current Wiki notes, active work, session state, selected references, and the skills the person required for this request. Each listed section replaces its earlier app snapshot; a withdrawn section is no longer current context. These updates are context, not requests from the user. Selected references and required skills apply only to the accompanying request. They do not change permissions. Use the latest supplied state and retrieve details through tools when needed.";
|
|
2684
2789
|
var CONTEXT_MESSAGE_TYPE = "xingular-context";
|
|
2685
2790
|
var CONTEXT_SNAPSHOT_KEY = "xingularContext";
|
|
2686
2791
|
function deliveredSnapshot(sessionFile2) {
|
|
2687
2792
|
let text10;
|
|
2688
2793
|
try {
|
|
2689
|
-
text10 =
|
|
2794
|
+
text10 = readFileSync8(sessionFile2, "utf8");
|
|
2690
2795
|
} catch {
|
|
2691
2796
|
return null;
|
|
2692
2797
|
}
|
|
@@ -2721,14 +2826,14 @@ function sessionFile(sessionDir, resume) {
|
|
|
2721
2826
|
if (resume) return resume;
|
|
2722
2827
|
let names2;
|
|
2723
2828
|
try {
|
|
2724
|
-
names2 =
|
|
2829
|
+
names2 = readdirSync7(sessionDir);
|
|
2725
2830
|
} catch {
|
|
2726
2831
|
return null;
|
|
2727
2832
|
}
|
|
2728
2833
|
const files3 = names2.filter((name) => name.endsWith(".jsonl") && name.length > ".jsonl".length).flatMap((name) => {
|
|
2729
|
-
const path4 =
|
|
2834
|
+
const path4 = join10(sessionDir, name);
|
|
2730
2835
|
try {
|
|
2731
|
-
return [{ path: path4, modified:
|
|
2836
|
+
return [{ path: path4, modified: statSync6(path4).mtimeMs }];
|
|
2732
2837
|
} catch {
|
|
2733
2838
|
return [];
|
|
2734
2839
|
}
|
|
@@ -2746,12 +2851,14 @@ function sessionLaunch(env, context, launch, historyFile, variant = null) {
|
|
|
2746
2851
|
const previous = historyFile ? deliveredSnapshot(historyFile) : null;
|
|
2747
2852
|
const snapshot2 = pack.sections.filter((entry2) => dynamic.includes(entry2.id));
|
|
2748
2853
|
const updated = [];
|
|
2749
|
-
|
|
2854
|
+
const updateSizes = {};
|
|
2855
|
+
const preamble = "[App context update \u2014 not a user message]\nListed sections replace their previous app snapshots.\n";
|
|
2856
|
+
let content = preamble;
|
|
2750
2857
|
for (const id of dynamic) {
|
|
2751
2858
|
const current2 = snapshot2.find((entry2) => entry2.id === id);
|
|
2752
|
-
if (previous && sameSection(current2, previous.find((entry2) => entry2.id === id)) && !(id === "references" && current2)) continue;
|
|
2859
|
+
if (previous && sameSection(current2, previous.find((entry2) => entry2.id === id)) && !(id === "references" && current2) && !(id === "required-skills" && current2)) continue;
|
|
2753
2860
|
updated.push(id);
|
|
2754
|
-
|
|
2861
|
+
const piece = current2 ? `
|
|
2755
2862
|
## ${current2.title}
|
|
2756
2863
|
|
|
2757
2864
|
${current2.body}
|
|
@@ -2760,25 +2867,39 @@ ${current2.body}
|
|
|
2760
2867
|
|
|
2761
2868
|
This section is not supplied for this request. Its earlier app snapshots are no longer current.
|
|
2762
2869
|
`;
|
|
2870
|
+
content += piece;
|
|
2871
|
+
updateSizes[id] = piece.length;
|
|
2763
2872
|
}
|
|
2764
2873
|
const stable = pack.sections.filter((entry2) => !dynamic.includes(entry2.id));
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
return { system: `${render(env, { sections: stable })}
|
|
2874
|
+
const rendered = renderSized(env, { sections: stable });
|
|
2875
|
+
const system = `${rendered.text}
|
|
2768
2876
|
## Context updates
|
|
2769
2877
|
|
|
2770
2878
|
${CONTEXT_GUIDANCE}
|
|
2771
|
-
|
|
2879
|
+
`;
|
|
2880
|
+
const total = (sizes) => Object.values(sizes).reduce((sum, size2) => sum + size2, 0);
|
|
2881
|
+
pack.delivery = {
|
|
2882
|
+
systemSectionIds: stable.map((entry2) => entry2.id),
|
|
2883
|
+
updatedSectionIds: updated,
|
|
2884
|
+
sizes: {
|
|
2885
|
+
system: rendered.sizes,
|
|
2886
|
+
update: updated.length ? updateSizes : {},
|
|
2887
|
+
systemFraming: system.length - total(rendered.sizes),
|
|
2888
|
+
updateFraming: updated.length ? content.length - total(updateSizes) : 0
|
|
2889
|
+
}
|
|
2890
|
+
};
|
|
2891
|
+
record(env.root, pack);
|
|
2892
|
+
return { system, update: updated.length ? { content, snapshot: snapshot2 } : null, pack };
|
|
2772
2893
|
}
|
|
2773
2894
|
function saveForSession(sessionDir, pack) {
|
|
2774
2895
|
try {
|
|
2775
|
-
writeJson(
|
|
2896
|
+
writeJson(join10(sessionDir, "context.json"), pack);
|
|
2776
2897
|
} catch {
|
|
2777
2898
|
}
|
|
2778
2899
|
}
|
|
2779
2900
|
function copyToRun(root, sessionDir, runId) {
|
|
2780
2901
|
try {
|
|
2781
|
-
const pack = readJson(
|
|
2902
|
+
const pack = readJson(join10(sessionDir, "context.json"));
|
|
2782
2903
|
if (pack) writeJson(packPath(root, runId), { ...pack, runId });
|
|
2783
2904
|
} catch {
|
|
2784
2905
|
}
|
|
@@ -2790,7 +2911,7 @@ function nativeId(sessionDir, path4) {
|
|
|
2790
2911
|
const file2 = realpathSync(path4);
|
|
2791
2912
|
const within2 = relative3(realpathSync(sessionDir), file2);
|
|
2792
2913
|
if (within2.startsWith("..") || isAbsolute2(within2) || !file2.endsWith(".jsonl")) throw new Error("Outside history");
|
|
2793
|
-
const header = JSON.parse(
|
|
2914
|
+
const header = JSON.parse(readFileSync9(file2, "utf8").split("\n", 1)[0]);
|
|
2794
2915
|
if (header.type !== "session" || !header.id) throw new Error("Missing session identity");
|
|
2795
2916
|
return header.id;
|
|
2796
2917
|
}
|
|
@@ -2817,13 +2938,13 @@ function selectHistory(selection) {
|
|
|
2817
2938
|
function findHistory(sessionDir, nativeSessionId) {
|
|
2818
2939
|
let names2;
|
|
2819
2940
|
try {
|
|
2820
|
-
names2 =
|
|
2941
|
+
names2 = readdirSync8(sessionDir).filter((name) => name.endsWith(".jsonl"));
|
|
2821
2942
|
} catch {
|
|
2822
2943
|
return null;
|
|
2823
2944
|
}
|
|
2824
2945
|
for (const name of names2) {
|
|
2825
2946
|
try {
|
|
2826
|
-
if (nativeId(sessionDir,
|
|
2947
|
+
if (nativeId(sessionDir, join11(sessionDir, name)) === nativeSessionId) return realpathSync(join11(sessionDir, name));
|
|
2827
2948
|
} catch {
|
|
2828
2949
|
}
|
|
2829
2950
|
}
|
|
@@ -2833,17 +2954,17 @@ function findHistory(sessionDir, nativeSessionId) {
|
|
|
2833
2954
|
// src/sessions/runStore.ts
|
|
2834
2955
|
init_errors();
|
|
2835
2956
|
init_fs();
|
|
2836
|
-
import { appendFileSync, copyFileSync as copyFileSync2, existsSync as
|
|
2837
|
-
import { join as
|
|
2957
|
+
import { appendFileSync, copyFileSync as copyFileSync2, existsSync as existsSync9, mkdirSync as mkdirSync5, readFileSync as readFileSync10 } from "node:fs";
|
|
2958
|
+
import { join as join14 } from "node:path";
|
|
2838
2959
|
|
|
2839
2960
|
// src/sessions/runIndex.ts
|
|
2840
2961
|
init_fs();
|
|
2841
|
-
import { join as
|
|
2962
|
+
import { join as join13 } from "node:path";
|
|
2842
2963
|
|
|
2843
2964
|
// src/core/index.ts
|
|
2844
2965
|
init_errors();
|
|
2845
|
-
import { copyFileSync, existsSync as
|
|
2846
|
-
import { join as
|
|
2966
|
+
import { copyFileSync, existsSync as existsSync8, readdirSync as readdirSync9, rmSync as rmSync5 } from "node:fs";
|
|
2967
|
+
import { join as join12 } from "node:path";
|
|
2847
2968
|
import { DatabaseSync } from "node:sqlite";
|
|
2848
2969
|
var RECALL_SCHEMA = `CREATE TABLE recall_runs (run_id TEXT PRIMARY KEY, passages INTEGER NOT NULL, status TEXT NOT NULL);
|
|
2849
2970
|
CREATE VIRTUAL TABLE recall_fts USING fts5(run_id UNINDEXED, seq UNINDEXED, role UNINDEXED, at UNINDEXED,
|
|
@@ -2910,7 +3031,7 @@ var MIGRATIONS = [
|
|
|
2910
3031
|
];
|
|
2911
3032
|
var connections = /* @__PURE__ */ new Map();
|
|
2912
3033
|
function dbPath(root) {
|
|
2913
|
-
return
|
|
3034
|
+
return join12(root, "index.sqlite");
|
|
2914
3035
|
}
|
|
2915
3036
|
function sqlError(error) {
|
|
2916
3037
|
return new HarnessError("index_error", error instanceof Error ? error.message : String(error), "Settings \u2192 Projects and Storage \u2192 Repair index.");
|
|
@@ -2946,7 +3067,7 @@ function migrate(path4, migrations) {
|
|
|
2946
3067
|
}
|
|
2947
3068
|
if (current2 >= migrations.length) return database;
|
|
2948
3069
|
const backup2 = `${path4.replace(/\.sqlite$/, "")}.sqlite.bak-v${current2}`;
|
|
2949
|
-
const hadFile =
|
|
3070
|
+
const hadFile = existsSync8(path4) && current2 > 0;
|
|
2950
3071
|
if (hadFile) {
|
|
2951
3072
|
try {
|
|
2952
3073
|
database.exec("PRAGMA wal_checkpoint(TRUNCATE);");
|
|
@@ -3001,7 +3122,7 @@ function run(database, sql, ...params) {
|
|
|
3001
3122
|
}
|
|
3002
3123
|
function runFolders(root) {
|
|
3003
3124
|
try {
|
|
3004
|
-
return
|
|
3125
|
+
return readdirSync9(join12(root, "runs"));
|
|
3005
3126
|
} catch {
|
|
3006
3127
|
return [];
|
|
3007
3128
|
}
|
|
@@ -3036,15 +3157,15 @@ function readAllRuns(root) {
|
|
|
3036
3157
|
const records = [];
|
|
3037
3158
|
for (const name of runFolders(root)) {
|
|
3038
3159
|
try {
|
|
3039
|
-
const parsed = runRecordSchema.safeParse(upgradeRunRecord(readJson(
|
|
3160
|
+
const parsed = runRecordSchema.safeParse(upgradeRunRecord(readJson(join13(root, "runs", name, "run.json"))));
|
|
3040
3161
|
if (parsed.success) records.push(parsed.data);
|
|
3041
3162
|
} catch {
|
|
3042
3163
|
}
|
|
3043
3164
|
}
|
|
3044
3165
|
return records;
|
|
3045
3166
|
}
|
|
3046
|
-
function runsForSession(root, sessionId,
|
|
3047
|
-
return withIndex(root, (database) => all(database, "SELECT id FROM runs WHERE session_id = ? ORDER BY started_at DESC LIMIT ?", sessionId,
|
|
3167
|
+
function runsForSession(root, sessionId, limit2) {
|
|
3168
|
+
return withIndex(root, (database) => all(database, "SELECT id FROM runs WHERE session_id = ? ORDER BY started_at DESC LIMIT ?", sessionId, limit2).map((row) => row.id));
|
|
3048
3169
|
}
|
|
3049
3170
|
function runsSince(root, filter, since) {
|
|
3050
3171
|
return withIndex(
|
|
@@ -3073,9 +3194,9 @@ function runsSince(root, filter, since) {
|
|
|
3073
3194
|
|
|
3074
3195
|
// src/sessions/runStore.ts
|
|
3075
3196
|
function runDir(root, runId) {
|
|
3076
|
-
return
|
|
3197
|
+
return join14(root, "runs", safeId(runId));
|
|
3077
3198
|
}
|
|
3078
|
-
var recordPath = (root, runId) =>
|
|
3199
|
+
var recordPath = (root, runId) => join14(runDir(root, runId), "run.json");
|
|
3079
3200
|
function ordered(record3) {
|
|
3080
3201
|
return {
|
|
3081
3202
|
resumedFromRunId: record3.resumedFromRunId,
|
|
@@ -3115,7 +3236,7 @@ function write2(root, record3) {
|
|
|
3115
3236
|
if (isActiveStatus(record3.status)) claimOwner(root, record3.id);
|
|
3116
3237
|
recordRun(root, record3);
|
|
3117
3238
|
}
|
|
3118
|
-
var ownerPath = (root, runId) =>
|
|
3239
|
+
var ownerPath = (root, runId) => join14(runDir(root, runId), "owner.json");
|
|
3119
3240
|
function claimOwner(root, runId) {
|
|
3120
3241
|
const path4 = ownerPath(root, runId);
|
|
3121
3242
|
if (readJsonOr(path4, null)?.pid === process.pid) return;
|
|
@@ -3153,10 +3274,10 @@ function findRun(root, runId) {
|
|
|
3153
3274
|
function recordSubagent(root, parentRunId, childRunId) {
|
|
3154
3275
|
loadRun2(root, parentRunId);
|
|
3155
3276
|
const ids2 = recordedSubagents(root, parentRunId);
|
|
3156
|
-
if (!ids2.includes(childRunId)) writeJson(
|
|
3277
|
+
if (!ids2.includes(childRunId)) writeJson(join14(runDir(root, parentRunId), "subagents.json"), [...ids2, childRunId]);
|
|
3157
3278
|
}
|
|
3158
3279
|
function recordedSubagents(root, parentRunId) {
|
|
3159
|
-
const value = readJson(
|
|
3280
|
+
const value = readJson(join14(runDir(root, parentRunId), "subagents.json"));
|
|
3160
3281
|
if (value === null) return [];
|
|
3161
3282
|
if (!Array.isArray(value) || value.some((id) => typeof id !== "string")) throw new Error("Recorded subagent ownership is unreadable.");
|
|
3162
3283
|
return value;
|
|
@@ -3184,7 +3305,7 @@ function reasonOf(event) {
|
|
|
3184
3305
|
function appendEvent(root, event) {
|
|
3185
3306
|
const directory = runDir(root, event.runId);
|
|
3186
3307
|
mkdirSync5(directory, { recursive: true });
|
|
3187
|
-
appendFileSync(
|
|
3308
|
+
appendFileSync(join14(directory, "events.jsonl"), `${JSON.stringify(event)}
|
|
3188
3309
|
`);
|
|
3189
3310
|
}
|
|
3190
3311
|
function storedEvent(line2) {
|
|
@@ -3199,7 +3320,7 @@ function storedEvent(line2) {
|
|
|
3199
3320
|
function readEvents(root, runId) {
|
|
3200
3321
|
let text10;
|
|
3201
3322
|
try {
|
|
3202
|
-
text10 =
|
|
3323
|
+
text10 = readFileSync10(join14(runDir(root, runId), "events.jsonl"), "utf8");
|
|
3203
3324
|
} catch (error) {
|
|
3204
3325
|
if (error.code === "ENOENT") return [];
|
|
3205
3326
|
throw error;
|
|
@@ -3252,7 +3373,7 @@ function markInterruptedRuns(root, reason = STOPPED) {
|
|
|
3252
3373
|
const settledReason = reasonOf(settled3);
|
|
3253
3374
|
if (record3.status !== status || record3.endedAt !== settled3.timestamp || record3.terminalReason !== settledReason) {
|
|
3254
3375
|
const backup2 = `${path4}.before-outcome-repair`;
|
|
3255
|
-
if (!
|
|
3376
|
+
if (!existsSync9(backup2)) copyFileSync2(path4, backup2);
|
|
3256
3377
|
Object.assign(record3, { status, endedAt: settled3.timestamp, terminalReason: settledReason });
|
|
3257
3378
|
write2(root, record3);
|
|
3258
3379
|
}
|
|
@@ -3428,6 +3549,41 @@ var WAIT_SUBAGENTS = "wait_subagents";
|
|
|
3428
3549
|
var SUBAGENT_RELATION = "subagent";
|
|
3429
3550
|
var DEFAULT_SUBAGENT_DEPTH = 1;
|
|
3430
3551
|
var MAX_SUBAGENT_DEPTH = 3;
|
|
3552
|
+
var DEFAULT_SUBAGENT_CHILDREN = 4;
|
|
3553
|
+
var MAX_SUBAGENT_CHILDREN = 50;
|
|
3554
|
+
var DEFAULT_SUBAGENT_PROFILE_CHILDREN = { worker: 2, explorer: 3 };
|
|
3555
|
+
var DEFAULT_SUBAGENT_OTHER_PROFILE = 1;
|
|
3556
|
+
var DEFAULT_SUBAGENT_UNPROFILED = 1;
|
|
3557
|
+
var UNPROFILED_SUBAGENT = "*";
|
|
3558
|
+
function limit(value, fallback) {
|
|
3559
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return fallback;
|
|
3560
|
+
return Math.min(MAX_SUBAGENT_CHILDREN, Math.max(0, Math.trunc(value)));
|
|
3561
|
+
}
|
|
3562
|
+
function subagentQuota(options2) {
|
|
3563
|
+
const profiles = { ...DEFAULT_SUBAGENT_PROFILE_CHILDREN };
|
|
3564
|
+
const given = options2?.maxByProfile;
|
|
3565
|
+
if (given && typeof given === "object" && !Array.isArray(given)) {
|
|
3566
|
+
for (const [raw, value] of Object.entries(given)) {
|
|
3567
|
+
const name = raw.trim();
|
|
3568
|
+
if (!name || name.length > 64 || /[\x00-\x1f\x7f]/u.test(name)) continue;
|
|
3569
|
+
if (typeof value !== "number" || !Number.isFinite(value)) continue;
|
|
3570
|
+
profiles[name] = limit(value, profiles[name] ?? DEFAULT_SUBAGENT_OTHER_PROFILE);
|
|
3571
|
+
}
|
|
3572
|
+
}
|
|
3573
|
+
return {
|
|
3574
|
+
children: limit(options2?.maxChildren, DEFAULT_SUBAGENT_CHILDREN),
|
|
3575
|
+
profiles,
|
|
3576
|
+
other: limit(options2?.maxOther, DEFAULT_SUBAGENT_OTHER_PROFILE),
|
|
3577
|
+
unprofiled: limit(options2?.maxUnprofiled, DEFAULT_SUBAGENT_UNPROFILED)
|
|
3578
|
+
};
|
|
3579
|
+
}
|
|
3580
|
+
function subagentProfileKey(profile) {
|
|
3581
|
+
const name = typeof profile === "string" ? profile.trim() : "";
|
|
3582
|
+
return name || UNPROFILED_SUBAGENT;
|
|
3583
|
+
}
|
|
3584
|
+
function subagentProfileLimit(quota, key) {
|
|
3585
|
+
return key === UNPROFILED_SUBAGENT ? quota.unprofiled : quota.profiles[key] ?? quota.other;
|
|
3586
|
+
}
|
|
3431
3587
|
function subagentDepth(options2) {
|
|
3432
3588
|
const value = Math.trunc(options2?.maxDepth ?? DEFAULT_SUBAGENT_DEPTH);
|
|
3433
3589
|
return Math.min(MAX_SUBAGENT_DEPTH, Math.max(1, Number.isFinite(value) ? value : DEFAULT_SUBAGENT_DEPTH));
|
|
@@ -3518,6 +3674,8 @@ var Subagents = class {
|
|
|
3518
3674
|
launch;
|
|
3519
3675
|
options;
|
|
3520
3676
|
parents = /* @__PURE__ */ new Map();
|
|
3677
|
+
/** Child runs reserved synchronously at spawn, before their record exists, so parallel calls cannot overspend. */
|
|
3678
|
+
reserved = /* @__PURE__ */ new Map();
|
|
3521
3679
|
runtimeSettingsByRun = /* @__PURE__ */ new Map();
|
|
3522
3680
|
/** Internal adapter contract: context comes from a live run, never from model arguments. */
|
|
3523
3681
|
register(input, accountId, capabilities, deferUntilPrompt = false) {
|
|
@@ -3541,6 +3699,10 @@ var Subagents = class {
|
|
|
3541
3699
|
runtimeSettings(runId) {
|
|
3542
3700
|
return this.runtimeSettingsByRun.get(runId) ?? null;
|
|
3543
3701
|
}
|
|
3702
|
+
/** The budget for a run, or the foundation defaults when it has not registered one. */
|
|
3703
|
+
quota(runId) {
|
|
3704
|
+
return subagentQuota(this.parents.get(runId)?.input.subagents ?? void 0);
|
|
3705
|
+
}
|
|
3544
3706
|
rememberRuntimeSettings(runId, settings) {
|
|
3545
3707
|
this.runtimeSettingsByRun.set(runId, settings);
|
|
3546
3708
|
if (this.runtimeSettingsByRun.size > 500) {
|
|
@@ -3620,46 +3782,62 @@ var Subagents = class {
|
|
|
3620
3782
|
if (!profile) throw invalid(`There is no agent profile named ${request2.agent.trim()}.`);
|
|
3621
3783
|
}
|
|
3622
3784
|
}
|
|
3623
|
-
|
|
3624
|
-
let variant = input.variant ?? null;
|
|
3625
|
-
let launch = input.launch;
|
|
3626
|
-
let model = input.model;
|
|
3627
|
-
let effort = input.effort;
|
|
3628
|
-
if (profile) {
|
|
3629
|
-
if (profile.source === "variant" || profile.variant === "none") variant = null;
|
|
3630
|
-
else if (profile.variant) variant = { scope: profile.variant.scope, version: profile.variant.version };
|
|
3631
|
-
if (profile.model) model = profile.model;
|
|
3632
|
-
if (profile.effort) effort = profile.effort;
|
|
3633
|
-
launch = { ...input.launch ?? {}, sections: [...(input.launch?.sections ?? []).filter((section2) => section2.id !== "subagent"), { id: "subagent", title: `Your role: ${profile.name}`, body: profile.instructions || profile.description, budget: 16e3, order: 22 }] };
|
|
3634
|
-
}
|
|
3635
|
-
const narrowed = input.plan ? { capabilities: planEligibility.capabilities, unavailable: planEligibility.unavailableTools } : narrowForProfile(capabilities, profile, request2.tools, this.options.descriptors?.() ?? []);
|
|
3636
|
-
const childCapabilities = narrowed.capabilities;
|
|
3637
|
-
const tools4 = childCapabilities.tools;
|
|
3785
|
+
const quota = subagentQuota(input.subagents ?? void 0);
|
|
3638
3786
|
const runId = randomUUID2();
|
|
3639
|
-
const
|
|
3640
|
-
const
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3787
|
+
const usage = this.usage(request2.parentRunId);
|
|
3788
|
+
const slot = (count, of = "") => `${count} ${of}subagent slot${count === 1 ? "" : "s"}`;
|
|
3789
|
+
if (usage.total >= quota.children) throw invalid(`This run has used its ${slot(quota.children)}. Do the remaining work yourself.`);
|
|
3790
|
+
const profileKey = subagentProfileKey(profile?.name);
|
|
3791
|
+
const profileLimit = subagentProfileLimit(quota, profileKey);
|
|
3792
|
+
const profileUsed = usage.byProfile.get(profileKey) ?? 0;
|
|
3793
|
+
if (profileUsed >= profileLimit) {
|
|
3794
|
+
const label = profileKey === UNPROFILED_SUBAGENT ? "unprofiled " : `${profileKey} `;
|
|
3795
|
+
throw invalid(`This run has used its ${slot(profileLimit, label)}. Do the remaining work yourself.`);
|
|
3796
|
+
}
|
|
3797
|
+
this.reserve(request2.parentRunId, runId, profileKey);
|
|
3798
|
+
try {
|
|
3799
|
+
await until(parent.ready, parent.stopped.signal);
|
|
3800
|
+
let variant = input.variant ?? null;
|
|
3801
|
+
let launch = input.launch;
|
|
3802
|
+
let model = input.model;
|
|
3803
|
+
let effort = input.effort;
|
|
3804
|
+
if (profile) {
|
|
3805
|
+
if (profile.source === "variant" || profile.variant === "none") variant = null;
|
|
3806
|
+
else if (profile.variant) variant = { scope: profile.variant.scope, version: profile.variant.version };
|
|
3807
|
+
if (profile.model) model = profile.model;
|
|
3808
|
+
if (profile.effort) effort = profile.effort;
|
|
3809
|
+
launch = { ...input.launch ?? {}, sections: [...(input.launch?.sections ?? []).filter((section2) => section2.id !== "subagent"), { id: "subagent", title: `Your role: ${profile.name}`, body: profile.instructions || profile.description, budget: 16e3, order: 22 }] };
|
|
3810
|
+
}
|
|
3811
|
+
const narrowed = input.plan ? { capabilities: planEligibility.capabilities, unavailable: planEligibility.unavailableTools } : narrowForProfile(capabilities, profile, request2.tools, this.options.descriptors?.() ?? []);
|
|
3812
|
+
const childCapabilities = narrowed.capabilities;
|
|
3813
|
+
const tools4 = childCapabilities.tools;
|
|
3814
|
+
const sessionId = randomUUID2();
|
|
3815
|
+
const child = {
|
|
3816
|
+
...input,
|
|
3817
|
+
run: { ...input.run, ...input.plan ? { worktreeId: null } : {}, id: runId, sessionId, parentRunId: request2.parentRunId, relation: SUBAGENT_RELATION, goal: takeChars(brief, 4e3), title: title2, attachmentCount: 0, resumedFromRunId: null, handoffId: null, profile: profile?.name ?? null },
|
|
3818
|
+
accountId,
|
|
3819
|
+
poolId: null,
|
|
3820
|
+
sessionDir: join15(input.sessionDir, "subagents", runId),
|
|
3821
|
+
resume: null,
|
|
3822
|
+
text: brief,
|
|
3823
|
+
images: void 0,
|
|
3824
|
+
requiresImageInput: false,
|
|
3825
|
+
preamble: null,
|
|
3826
|
+
caller: { ...input.caller, runId: void 0, sessionId },
|
|
3827
|
+
tools: { allow: tools4, gated: (input.tools.gated ?? []).filter((name) => tools4.includes(name)) },
|
|
3828
|
+
capabilities: childCapabilities,
|
|
3829
|
+
depth: (input.depth ?? 0) + 1,
|
|
3830
|
+
variant,
|
|
3831
|
+
launch,
|
|
3832
|
+
model,
|
|
3833
|
+
effort,
|
|
3834
|
+
...input.plan ? { connections: false, subagents: null } : {}
|
|
3835
|
+
};
|
|
3836
|
+
const result = await this.launchChild(parent, request2, child);
|
|
3837
|
+
return { ...result, ...profile ? { agent: profile.name } : {}, ...narrowed.unavailable.length ? { unavailableTools: narrowed.unavailable } : {} };
|
|
3838
|
+
} finally {
|
|
3839
|
+
this.release(request2.parentRunId, runId);
|
|
3840
|
+
}
|
|
3663
3841
|
}
|
|
3664
3842
|
/** Records ownership, starts the child, and writes a failed record when it never opened. */
|
|
3665
3843
|
async launchChild(parent, request2, child) {
|
|
@@ -3683,6 +3861,56 @@ var Subagents = class {
|
|
|
3683
3861
|
owned(parentRunId, parent) {
|
|
3684
3862
|
return /* @__PURE__ */ new Set([...recordedSubagents(this.env.root, parentRunId), ...parent?.recovered ?? []]);
|
|
3685
3863
|
}
|
|
3864
|
+
/** The run and the runs it was continued from, so a work-slice continuation keeps the budget. */
|
|
3865
|
+
ancestry(runId) {
|
|
3866
|
+
const chain = [];
|
|
3867
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3868
|
+
let current2 = runId;
|
|
3869
|
+
while (current2 && !seen.has(current2) && chain.length < 20) {
|
|
3870
|
+
seen.add(current2);
|
|
3871
|
+
chain.push(current2);
|
|
3872
|
+
current2 = findRun(this.env.root, current2)?.resumedFromRunId ?? null;
|
|
3873
|
+
}
|
|
3874
|
+
return chain;
|
|
3875
|
+
}
|
|
3876
|
+
/** Distinct child conversations this run has started, plus slots reserved before their record exists. */
|
|
3877
|
+
usage(parentRunId) {
|
|
3878
|
+
const byProfile = /* @__PURE__ */ new Map();
|
|
3879
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3880
|
+
let total = 0;
|
|
3881
|
+
const add = (key) => {
|
|
3882
|
+
total += 1;
|
|
3883
|
+
byProfile.set(key, (byProfile.get(key) ?? 0) + 1);
|
|
3884
|
+
};
|
|
3885
|
+
for (const owner of this.ancestry(parentRunId)) {
|
|
3886
|
+
for (const id of recordedSubagents(this.env.root, owner)) {
|
|
3887
|
+
const record3 = findRun(this.env.root, id);
|
|
3888
|
+
if (!record3 || record3.relation !== SUBAGENT_RELATION) continue;
|
|
3889
|
+
const first = this.firstLink(record3).id;
|
|
3890
|
+
if (seen.has(first)) continue;
|
|
3891
|
+
seen.add(first);
|
|
3892
|
+
add(subagentProfileKey(record3.profile));
|
|
3893
|
+
}
|
|
3894
|
+
}
|
|
3895
|
+
const reserved = this.reserved.get(parentRunId);
|
|
3896
|
+
if (reserved) for (const [id, key] of reserved) {
|
|
3897
|
+
if (seen.has(id) || findRun(this.env.root, id)) continue;
|
|
3898
|
+
seen.add(id);
|
|
3899
|
+
add(key);
|
|
3900
|
+
}
|
|
3901
|
+
return { total, byProfile };
|
|
3902
|
+
}
|
|
3903
|
+
reserve(parentRunId, runId, profile) {
|
|
3904
|
+
const reserved = this.reserved.get(parentRunId) ?? /* @__PURE__ */ new Map();
|
|
3905
|
+
reserved.set(runId, profile);
|
|
3906
|
+
this.reserved.set(parentRunId, reserved);
|
|
3907
|
+
}
|
|
3908
|
+
release(parentRunId, runId) {
|
|
3909
|
+
const reserved = this.reserved.get(parentRunId);
|
|
3910
|
+
if (!reserved) return;
|
|
3911
|
+
reserved.delete(runId);
|
|
3912
|
+
if (!reserved.size) this.reserved.delete(parentRunId);
|
|
3913
|
+
}
|
|
3686
3914
|
/** The newest run in a continued child's chain, among the runs this parent owns. */
|
|
3687
3915
|
latestLink(start, owned) {
|
|
3688
3916
|
const records = [...owned].flatMap((id) => findRun(this.env.root, id) ?? []);
|
|
@@ -3726,7 +3954,7 @@ var Subagents = class {
|
|
|
3726
3954
|
const latest = this.latestLink(named2, owned);
|
|
3727
3955
|
if (isActiveStatus(latest.status)) throw invalid(`Subagent ${latest.id} is still running; wait for it with wait_subagents.`);
|
|
3728
3956
|
if (latest.status === "completed") throw invalid(`Subagent ${latest.id} already finished and its result was delivered. Start a new subagent for more work.`);
|
|
3729
|
-
const sessionDir =
|
|
3957
|
+
const sessionDir = join15(input.sessionDir, "subagents", this.firstLink(latest).id);
|
|
3730
3958
|
const continuation = continuationOf(root, latest.id, sessionDir);
|
|
3731
3959
|
if (!continuation.resumable || !continuation.resume) throw invalid(`Subagent ${latest.id} cannot be continued: ${continuation.reason === "no_history" ? "it stopped before its conversation started" : "its saved conversation is missing"}. Start a new subagent instead.`);
|
|
3732
3960
|
if (continuation.accountId !== accountId) throw invalid(`Subagent ${latest.id} ran on another account; start a new subagent instead.`);
|
|
@@ -3883,17 +4111,17 @@ It stopped before finishing. ${continueHint(result.runId)}` : ""}`;
|
|
|
3883
4111
|
|
|
3884
4112
|
// src/harness.ts
|
|
3885
4113
|
import { mkdirSync as mkdirSync26 } from "node:fs";
|
|
3886
|
-
import { join as
|
|
4114
|
+
import { join as join69 } from "node:path";
|
|
3887
4115
|
|
|
3888
4116
|
// src/accounts/accounts.ts
|
|
3889
|
-
import { chmodSync as chmodSync3, existsSync as
|
|
4117
|
+
import { chmodSync as chmodSync3, existsSync as existsSync10, mkdirSync as mkdirSync9, readdirSync as readdirSync11, rmSync as rmSync7 } from "node:fs";
|
|
3890
4118
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
3891
|
-
import { join as
|
|
4119
|
+
import { join as join21 } from "node:path";
|
|
3892
4120
|
init_errors();
|
|
3893
4121
|
init_fs();
|
|
3894
4122
|
|
|
3895
4123
|
// src/pi/runtime.ts
|
|
3896
|
-
import { join as
|
|
4124
|
+
import { join as join16 } from "node:path";
|
|
3897
4125
|
import { pathToFileURL } from "node:url";
|
|
3898
4126
|
var PINNED_PI_VERSION = "1.4.0";
|
|
3899
4127
|
var HTTP_DISPATCHER_CHUNK = "dist/bundle/chunks/chunk-MM3LKT73.js";
|
|
@@ -3923,17 +4151,17 @@ function createPiLoader(importPi, importDispatcher) {
|
|
|
3923
4151
|
}
|
|
3924
4152
|
var loadPi = createPiLoader(
|
|
3925
4153
|
() => import("@earendil-works/pi-coding-agent"),
|
|
3926
|
-
async (packageDir) => await import(pathToFileURL(
|
|
4154
|
+
async (packageDir) => await import(pathToFileURL(join16(packageDir, HTTP_DISPATCHER_CHUNK)).href)
|
|
3927
4155
|
);
|
|
3928
4156
|
|
|
3929
4157
|
// src/accounts/choices.ts
|
|
3930
|
-
import { join as
|
|
4158
|
+
import { join as join17 } from "node:path";
|
|
3931
4159
|
init_errors();
|
|
3932
4160
|
init_fs();
|
|
3933
4161
|
var MODE = /^[a-z][a-z0-9_-]{0,31}$/;
|
|
3934
4162
|
var MODEL = /^[^\s/]+\/\S+$/;
|
|
3935
4163
|
var MAX_MODEL = 200;
|
|
3936
|
-
var choicesPath = (dir2, accountId) =>
|
|
4164
|
+
var choicesPath = (dir2, accountId) => join17(dir2, safeId(accountId), "choices.json");
|
|
3937
4165
|
var validModel = (model) => model.length <= MAX_MODEL && MODEL.test(model);
|
|
3938
4166
|
var validEffort = (effort) => typeof effort === "string" && EFFORTS.includes(effort);
|
|
3939
4167
|
function validChoice(entry2) {
|
|
@@ -3971,9 +4199,9 @@ function saveChoice(dir2, accountId, mode2, patch) {
|
|
|
3971
4199
|
|
|
3972
4200
|
// src/accounts/env.ts
|
|
3973
4201
|
init_errors();
|
|
3974
|
-
import { chmodSync, copyFileSync as copyFileSync3, linkSync, lstatSync, mkdirSync as mkdirSync6, readlinkSync, renameSync as renameSync3, rmdirSync, statSync as
|
|
4202
|
+
import { chmodSync, copyFileSync as copyFileSync3, linkSync, lstatSync, mkdirSync as mkdirSync6, readlinkSync, renameSync as renameSync3, rmdirSync, statSync as statSync7, symlinkSync, unlinkSync as unlinkSync2, utimesSync } from "node:fs";
|
|
3975
4203
|
import { homedir } from "node:os";
|
|
3976
|
-
import { basename as basename3, dirname as
|
|
4204
|
+
import { basename as basename3, dirname as dirname6, join as join18, resolve as resolve2, sep as sep4 } from "node:path";
|
|
3977
4205
|
var DIR_VARS = ["CODEX_HOME", "CLAUDE_CONFIG_DIR", "PI_CODING_AGENT_DIR"];
|
|
3978
4206
|
function isCredentialVar(name) {
|
|
3979
4207
|
const upper = name.toUpperCase();
|
|
@@ -3986,13 +4214,13 @@ function inheritedCredentialVars(env = process.env) {
|
|
|
3986
4214
|
}
|
|
3987
4215
|
function isolateProcess(accountsDir, env = process.env) {
|
|
3988
4216
|
for (const name of inheritedCredentialVars(env)) delete env[name];
|
|
3989
|
-
const fallback =
|
|
4217
|
+
const fallback = join18(accountsDir, ".sidecar", "pi");
|
|
3990
4218
|
mkdirSync6(fallback, { recursive: true });
|
|
3991
4219
|
env.PI_CODING_AGENT_DIR = fallback;
|
|
3992
4220
|
}
|
|
3993
|
-
var homeDir = (accountsDir, accountId) =>
|
|
3994
|
-
var configDir = (accountsDir, account) =>
|
|
3995
|
-
var sharedDir = (accountsDir) =>
|
|
4221
|
+
var homeDir = (accountsDir, accountId) => join18(accountsDir, accountId, "home");
|
|
4222
|
+
var configDir = (accountsDir, account) => join18(homeDir(accountsDir, account.id), "pi");
|
|
4223
|
+
var sharedDir = (accountsDir) => join18(accountsDir, "_shared", "pi");
|
|
3996
4224
|
function makePrivate(path4) {
|
|
3997
4225
|
mkdirSync6(path4, { recursive: true });
|
|
3998
4226
|
chmodSync(path4, 448);
|
|
@@ -4020,7 +4248,7 @@ var present = (path4) => {
|
|
|
4020
4248
|
};
|
|
4021
4249
|
function nativeConfig(accountsDir) {
|
|
4022
4250
|
const shared = sharedDir(accountsDir);
|
|
4023
|
-
return { provider: "pi", path: shared, entries: SHARED_ENTRIES.map(([name, directory]) => ({ name, directory, present: present(
|
|
4251
|
+
return { provider: "pi", path: shared, entries: SHARED_ENTRIES.map(([name, directory]) => ({ name, directory, present: present(join18(shared, name)) })) };
|
|
4024
4252
|
}
|
|
4025
4253
|
function ensureSharedDir(accountsDir) {
|
|
4026
4254
|
const shared = sharedDir(accountsDir);
|
|
@@ -4035,7 +4263,7 @@ var modified = (path4) => {
|
|
|
4035
4263
|
}
|
|
4036
4264
|
};
|
|
4037
4265
|
function backUp(path4) {
|
|
4038
|
-
const backup2 =
|
|
4266
|
+
const backup2 = join18(dirname6(path4), `${basename3(path4)}.xagent-backup-${Math.floor(Date.now() / 1e3)}`);
|
|
4039
4267
|
renameSync3(path4, backup2);
|
|
4040
4268
|
return backup2;
|
|
4041
4269
|
}
|
|
@@ -4098,7 +4326,7 @@ function keepCopy(target, path4, isDir2) {
|
|
|
4098
4326
|
if (isDir2 || present(path4) || !present(target)) return;
|
|
4099
4327
|
try {
|
|
4100
4328
|
copyFileSync3(target, path4);
|
|
4101
|
-
const { atime, mtime } =
|
|
4329
|
+
const { atime, mtime } = statSync7(target);
|
|
4102
4330
|
utimesSync(path4, atime, mtime);
|
|
4103
4331
|
} catch {
|
|
4104
4332
|
}
|
|
@@ -4143,12 +4371,12 @@ function linkOne(name, target, path4, isDir2, linker) {
|
|
|
4143
4371
|
}
|
|
4144
4372
|
}
|
|
4145
4373
|
function linkSharedEntries(accountsDir, account, linker = nodeLinker) {
|
|
4146
|
-
makePrivate(
|
|
4374
|
+
makePrivate(join18(accountsDir, account.id));
|
|
4147
4375
|
makePrivate(homeDir(accountsDir, account.id));
|
|
4148
4376
|
const dir2 = configDir(accountsDir, account);
|
|
4149
4377
|
makePrivate(dir2);
|
|
4150
4378
|
const shared = ensureSharedDir(accountsDir);
|
|
4151
|
-
const entries2 = SHARED_ENTRIES.map(([name, isDir2]) => linkOne(name,
|
|
4379
|
+
const entries2 = SHARED_ENTRIES.map(([name, isDir2]) => linkOne(name, join18(shared, name), join18(dir2, name), isDir2, linker));
|
|
4152
4380
|
return { dir: dir2, entries: entries2 };
|
|
4153
4381
|
}
|
|
4154
4382
|
function ensureHome(accountsDir, account) {
|
|
@@ -4156,7 +4384,7 @@ function ensureHome(accountsDir, account) {
|
|
|
4156
4384
|
}
|
|
4157
4385
|
var inside = (path4, parent) => path4 === parent || path4.startsWith(parent.endsWith(sep4) ? parent : `${parent}${sep4}`);
|
|
4158
4386
|
function assertIsolated(accountsDir, dir2) {
|
|
4159
|
-
const defaults = [".codex", ".claude", ".pi"].map((name) =>
|
|
4387
|
+
const defaults = [".codex", ".claude", ".pi"].map((name) => join18(homedir() || "/", name));
|
|
4160
4388
|
if (defaults.some((folder2) => inside(dir2, folder2)) || !inside(dir2, accountsDir)) {
|
|
4161
4389
|
throw new HarnessError("account_required", "A session cannot start outside its isolated account folder.");
|
|
4162
4390
|
}
|
|
@@ -4180,12 +4408,12 @@ function accountContext(accountsDir, account) {
|
|
|
4180
4408
|
|
|
4181
4409
|
// src/accounts/secrets.ts
|
|
4182
4410
|
init_fs();
|
|
4183
|
-
import { chmodSync as chmodSync2, closeSync as closeSync2, fsyncSync as fsyncSync2, lstatSync as lstatSync2, mkdirSync as mkdirSync7, openSync as openSync2, readdirSync as
|
|
4411
|
+
import { chmodSync as chmodSync2, closeSync as closeSync2, fsyncSync as fsyncSync2, lstatSync as lstatSync2, mkdirSync as mkdirSync7, openSync as openSync2, readdirSync as readdirSync10, readFileSync as readFileSync11, renameSync as renameSync4, rmSync as rmSync6, writeFileSync as writeFileSync2 } from "node:fs";
|
|
4184
4412
|
import { createHash as createHash2, randomUUID as randomUUID3 } from "node:crypto";
|
|
4185
|
-
import { dirname as
|
|
4413
|
+
import { dirname as dirname7, join as join19 } from "node:path";
|
|
4186
4414
|
import { performance } from "node:perf_hooks";
|
|
4187
4415
|
function privateWrite(path4, value) {
|
|
4188
|
-
const temporary =
|
|
4416
|
+
const temporary = join19(dirname7(path4), `.credential-${randomUUID3()}.tmp`);
|
|
4189
4417
|
try {
|
|
4190
4418
|
const fd = openSync2(temporary, "wx", 384);
|
|
4191
4419
|
try {
|
|
@@ -4206,17 +4434,17 @@ async function withCredentialLock(dir2, key, work2, options2 = {}) {
|
|
|
4206
4434
|
throw new Error("Invalid credential lock wait bounds.");
|
|
4207
4435
|
}
|
|
4208
4436
|
const started = performance.now();
|
|
4209
|
-
const folder2 =
|
|
4437
|
+
const folder2 = join19(dir2, createHash2("sha256").update(key).digest("hex"));
|
|
4210
4438
|
mkdirSync7(folder2, { recursive: true, mode: 448 });
|
|
4211
4439
|
if (!lstatSync2(dir2).isDirectory() || !lstatSync2(folder2).isDirectory()) throw new Error("Invalid credential lock directory.");
|
|
4212
4440
|
chmodSync2(dir2, 448);
|
|
4213
4441
|
chmodSync2(folder2, 448);
|
|
4214
4442
|
const id = `${process.pid}-${randomUUID3()}`;
|
|
4215
|
-
const own =
|
|
4443
|
+
const own = join19(folder2, id);
|
|
4216
4444
|
mkdirSync7(own, { mode: 448 });
|
|
4217
4445
|
const participants = () => {
|
|
4218
4446
|
const entries2 = [];
|
|
4219
|
-
for (const name of
|
|
4447
|
+
for (const name of readdirSync10(folder2)) {
|
|
4220
4448
|
if (!/^\d+-[0-9a-f-]{36}$/.test(name)) throw new Error("Invalid credential lock metadata.");
|
|
4221
4449
|
const pid = Number(name.slice(0, name.indexOf("-")));
|
|
4222
4450
|
if (!Number.isSafeInteger(pid) || pid <= 0) throw new Error("Invalid credential lock metadata.");
|
|
@@ -4226,13 +4454,13 @@ async function withCredentialLock(dir2, key, work2, options2 = {}) {
|
|
|
4226
4454
|
} catch (error) {
|
|
4227
4455
|
if (error.code === "ESRCH") alive2 = false;
|
|
4228
4456
|
}
|
|
4229
|
-
const participant =
|
|
4457
|
+
const participant = join19(folder2, name);
|
|
4230
4458
|
if (!alive2) {
|
|
4231
4459
|
rmSync6(participant, { recursive: true, force: true });
|
|
4232
4460
|
continue;
|
|
4233
4461
|
}
|
|
4234
4462
|
try {
|
|
4235
|
-
const text10 =
|
|
4463
|
+
const text10 = readFileSync11(join19(participant, "ticket"), "utf8");
|
|
4236
4464
|
const ticket = Number(text10);
|
|
4237
4465
|
if (!Number.isSafeInteger(ticket) || ticket <= 0) throw new Error("Invalid credential lock metadata.");
|
|
4238
4466
|
entries2.push({ id: name, ticket });
|
|
@@ -4245,7 +4473,7 @@ async function withCredentialLock(dir2, key, work2, options2 = {}) {
|
|
|
4245
4473
|
};
|
|
4246
4474
|
try {
|
|
4247
4475
|
const ticket = Math.max(0, ...participants().map((entry2) => entry2.ticket ?? 0)) + 1;
|
|
4248
|
-
privateWrite(
|
|
4476
|
+
privateWrite(join19(own, "ticket"), String(ticket));
|
|
4249
4477
|
for (; ; ) {
|
|
4250
4478
|
const blocked = participants().some((entry2) => entry2.id !== id && (entry2.ticket === null || entry2.ticket < ticket || entry2.ticket === ticket && entry2.id < id));
|
|
4251
4479
|
if (!blocked) return await work2();
|
|
@@ -4269,7 +4497,7 @@ var secretKey = (accountId, name) => `${accountId}/${name}`;
|
|
|
4269
4497
|
function fileSecretStore(path4) {
|
|
4270
4498
|
const read5 = () => readJsonOr(path4, {});
|
|
4271
4499
|
const write4 = (values2) => {
|
|
4272
|
-
mkdirSync7(
|
|
4500
|
+
mkdirSync7(dirname7(path4), { recursive: true, mode: 448 });
|
|
4273
4501
|
privateWrite(path4, `${JSON.stringify(values2, null, 2)}
|
|
4274
4502
|
`);
|
|
4275
4503
|
chmodSync2(path4, 384);
|
|
@@ -4290,12 +4518,12 @@ function fileSecretStore(path4) {
|
|
|
4290
4518
|
// src/accounts/store.ts
|
|
4291
4519
|
init_errors();
|
|
4292
4520
|
init_fs();
|
|
4293
|
-
import { mkdirSync as mkdirSync8, readFileSync as
|
|
4294
|
-
import { join as
|
|
4521
|
+
import { mkdirSync as mkdirSync8, readFileSync as readFileSync12 } from "node:fs";
|
|
4522
|
+
import { join as join20 } from "node:path";
|
|
4295
4523
|
var PROVIDER = "pi";
|
|
4296
4524
|
var emptyState = () => ({ health: "unknown", signedIn: null, authMethod: null, plan: null, identity: null, limits: [], providerLimits: [], lastError: null, lastCheckedAt: null, cliVersion: null, capabilities: [], piProviders: [] });
|
|
4297
|
-
var registryPath = (dir2) =>
|
|
4298
|
-
var statePath = (dir2, accountId) =>
|
|
4525
|
+
var registryPath = (dir2) => join20(dir2, "accounts.json");
|
|
4526
|
+
var statePath = (dir2, accountId) => join20(dir2, safeId(accountId), "state.json");
|
|
4299
4527
|
function loadRegistry(dir2) {
|
|
4300
4528
|
const stored = readJsonOr(registryPath(dir2), {}) ?? {};
|
|
4301
4529
|
return { accounts: stored.accounts ?? [], defaults: stored.defaults ?? {}, pools: stored.pools ?? [], migratedProviderKeys: stored.migratedProviderKeys ?? false };
|
|
@@ -4325,14 +4553,14 @@ function scrub(text10) {
|
|
|
4325
4553
|
function audit(dir2, accountId, action, detail) {
|
|
4326
4554
|
try {
|
|
4327
4555
|
mkdirSync8(dir2, { recursive: true });
|
|
4328
|
-
appendLine(
|
|
4556
|
+
appendLine(join20(dir2, "audit.jsonl"), JSON.stringify({ at: now(), accountId, action, detail: scrub(detail) }));
|
|
4329
4557
|
} catch {
|
|
4330
4558
|
}
|
|
4331
4559
|
}
|
|
4332
|
-
function readAudit(dir2, accountId,
|
|
4560
|
+
function readAudit(dir2, accountId, limit2 = 100) {
|
|
4333
4561
|
let text10 = "";
|
|
4334
4562
|
try {
|
|
4335
|
-
text10 =
|
|
4563
|
+
text10 = readFileSync12(join20(dir2, "audit.jsonl"), "utf8");
|
|
4336
4564
|
} catch {
|
|
4337
4565
|
text10 = "";
|
|
4338
4566
|
}
|
|
@@ -4344,7 +4572,7 @@ function readAudit(dir2, accountId, limit = 100) {
|
|
|
4344
4572
|
return [];
|
|
4345
4573
|
}
|
|
4346
4574
|
});
|
|
4347
|
-
return entries2.reverse().slice(0, Math.min(
|
|
4575
|
+
return entries2.reverse().slice(0, Math.min(limit2, 1e3));
|
|
4348
4576
|
}
|
|
4349
4577
|
function inFuture(timestamp) {
|
|
4350
4578
|
const time = timestamp ? Date.parse(timestamp) : Number.NaN;
|
|
@@ -4358,7 +4586,7 @@ function limitErrorActive(issue) {
|
|
|
4358
4586
|
return !Number.isNaN(at) && Math.trunc((Date.now() - at) / 1e3) < UNTIMED_LIMIT_ERROR_SECS;
|
|
4359
4587
|
}
|
|
4360
4588
|
function deriveHealth(state) {
|
|
4361
|
-
const limitedByWindow = state.limits.some((
|
|
4589
|
+
const limitedByWindow = state.limits.some((limit2) => (limit2.status === "rejected" || (limit2.usedPercent ?? 0) >= 100) && (!limit2.resetsAt || inFuture(limit2.resetsAt)));
|
|
4362
4590
|
const issue = state.lastError;
|
|
4363
4591
|
if (issue?.category === "auth_expired") return "auth_expired";
|
|
4364
4592
|
if (issue && isLimitCategory(issue.category) && limitErrorActive(issue)) return "limited";
|
|
@@ -4396,7 +4624,7 @@ function resolve3(dir2, accountId, poolId) {
|
|
|
4396
4624
|
if (ready) return ready;
|
|
4397
4625
|
const resets = members.flatMap((account2) => {
|
|
4398
4626
|
const state = loadState(dir2, account2.id);
|
|
4399
|
-
return [...state.limits.map((
|
|
4627
|
+
return [...state.limits.map((limit2) => limit2.resetsAt), state.lastError?.resetsAt].filter((reset) => Boolean(reset));
|
|
4400
4628
|
});
|
|
4401
4629
|
const earliest = resets.sort(compareText)[0];
|
|
4402
4630
|
throw new HarnessError("account_unavailable", `Every account in ${pool.label} is unavailable.`, earliest ? `The earliest reset is ${earliest}.` : "Reauthenticate an account in Accounts.");
|
|
@@ -4493,7 +4721,7 @@ function classifyMessage(message4) {
|
|
|
4493
4721
|
if (/econnrefused|enotfound|etimedout|network|socket hang up|fetch failed/.test(text10)) return "network";
|
|
4494
4722
|
return null;
|
|
4495
4723
|
}
|
|
4496
|
-
var leaseFolder = (dir2, accountId) =>
|
|
4724
|
+
var leaseFolder = (dir2, accountId) => join21(dir2, accountId, "terminal-leases");
|
|
4497
4725
|
function processAlive(pid) {
|
|
4498
4726
|
try {
|
|
4499
4727
|
process.kill(pid, 0);
|
|
@@ -4581,7 +4809,7 @@ var Accounts = class {
|
|
|
4581
4809
|
}
|
|
4582
4810
|
}
|
|
4583
4811
|
credentialLock(key, work2) {
|
|
4584
|
-
return withCredentialLock(
|
|
4812
|
+
return withCredentialLock(join21(this.dir, ".credential-locks"), key, work2, this.credentialLockOptions);
|
|
4585
4813
|
}
|
|
4586
4814
|
/** Stores a provider's credential, or removes it when `credential` is `null`. */
|
|
4587
4815
|
async writeCredential(accountId, provider, credential) {
|
|
@@ -4653,7 +4881,7 @@ var Accounts = class {
|
|
|
4653
4881
|
let runtime = this.runtimes.get(id);
|
|
4654
4882
|
if (!runtime) {
|
|
4655
4883
|
const configDir2 = "configDir" in account ? account.configDir : ensureHome(this.dir, account);
|
|
4656
|
-
runtime = loadPi().then(({ ModelRuntime }) => ModelRuntime.create({ credentials: this.credentialStore(id), modelsPath:
|
|
4884
|
+
runtime = loadPi().then(({ ModelRuntime }) => ModelRuntime.create({ credentials: this.credentialStore(id), modelsPath: join21(configDir2, "models.json") })).then((created) => {
|
|
4657
4885
|
try {
|
|
4658
4886
|
this.observeModels?.(created, id);
|
|
4659
4887
|
} catch {
|
|
@@ -4683,7 +4911,7 @@ var Accounts = class {
|
|
|
4683
4911
|
const { ModelRuntime } = await loadPi();
|
|
4684
4912
|
const credentials = this.credentialStore(accountId);
|
|
4685
4913
|
const readOnly = { read: credentials.read, list: credentials.list, modify: async () => void 0, delete: async () => void 0 };
|
|
4686
|
-
const runtime = await ModelRuntime.create({ credentials: readOnly, modelsPath:
|
|
4914
|
+
const runtime = await ModelRuntime.create({ credentials: readOnly, modelsPath: join21(configDir(this.dir, { id: accountId }), "models.json"), refreshOnCreate: false, allowModelNetwork: false, signal });
|
|
4687
4915
|
const saved = await runtime.listCredentials({ signal });
|
|
4688
4916
|
const providers = new Set(saved.map((item) => item.providerId));
|
|
4689
4917
|
return { credentials: saved.length, models: runtime.getModels().filter((model) => providers.has(String(model.provider))).map((model) => ({ id: `${model.provider}/${model.id}`, name: model.name || model.id, provider: String(model.provider), supportsImages: model.input.includes("image"), reasoning: model.reasoning })) };
|
|
@@ -4785,7 +5013,7 @@ var Accounts = class {
|
|
|
4785
5013
|
await this.forgetCredentials(account).catch(() => void 0);
|
|
4786
5014
|
await this.secrets.delete(secretKey(account.id, "apiKey")).catch(() => void 0);
|
|
4787
5015
|
forgetAccount(this.dir, account);
|
|
4788
|
-
rmSync7(
|
|
5016
|
+
rmSync7(join21(this.dir, safeId(account.id)), { recursive: true, force: true });
|
|
4789
5017
|
audit(this.dir, account.id, "account.deleted", `"${account.label}" and its stored sign-in were removed.`);
|
|
4790
5018
|
this.changed({ accountId: account.id });
|
|
4791
5019
|
return this.overview();
|
|
@@ -4999,12 +5227,12 @@ var Accounts = class {
|
|
|
4999
5227
|
const count = (this.terminals.get(account.id) ?? 0) + 1;
|
|
5000
5228
|
this.terminals.set(account.id, count);
|
|
5001
5229
|
if (count > 1) return;
|
|
5002
|
-
const path4 =
|
|
5230
|
+
const path4 = join21(configDir(this.dir, account), "auth.json");
|
|
5003
5231
|
let shared = false;
|
|
5004
5232
|
try {
|
|
5005
5233
|
shared = this.otherTerminalProcesses(account.id);
|
|
5006
5234
|
this.claimLease(account.id);
|
|
5007
|
-
const existing = shared &&
|
|
5235
|
+
const existing = shared && existsSync10(path4) ? readAuth(path4) : null;
|
|
5008
5236
|
const data = await this.storedCredentials(account.id, existing ?? {});
|
|
5009
5237
|
if (!existing || Object.keys(data).length > Object.keys(existing).length) {
|
|
5010
5238
|
atomicWrite(path4, JSON.stringify(data, null, 2));
|
|
@@ -5036,7 +5264,7 @@ var Accounts = class {
|
|
|
5036
5264
|
const snapshot2 = this.terminalSnapshots.get(account.id) ?? {};
|
|
5037
5265
|
this.terminalSnapshots.delete(account.id);
|
|
5038
5266
|
this.releaseLease(account.id);
|
|
5039
|
-
const path4 =
|
|
5267
|
+
const path4 = join21(configDir(this.dir, account), "auth.json");
|
|
5040
5268
|
const data = readAuth(path4);
|
|
5041
5269
|
if (data) {
|
|
5042
5270
|
let changed2 = false;
|
|
@@ -5075,7 +5303,7 @@ var Accounts = class {
|
|
|
5075
5303
|
const folder2 = leaseFolder(this.dir, accountId);
|
|
5076
5304
|
let names2;
|
|
5077
5305
|
try {
|
|
5078
|
-
names2 =
|
|
5306
|
+
names2 = readdirSync11(folder2);
|
|
5079
5307
|
} catch {
|
|
5080
5308
|
return false;
|
|
5081
5309
|
}
|
|
@@ -5084,17 +5312,17 @@ var Accounts = class {
|
|
|
5084
5312
|
const pid = Number(name);
|
|
5085
5313
|
if (!/^\d+$/.test(name) || pid <= 0 || pid === process.pid) continue;
|
|
5086
5314
|
if (processAlive(pid)) others = true;
|
|
5087
|
-
else rmSync7(
|
|
5315
|
+
else rmSync7(join21(folder2, name), { force: true });
|
|
5088
5316
|
}
|
|
5089
5317
|
return others;
|
|
5090
5318
|
}
|
|
5091
5319
|
claimLease(accountId) {
|
|
5092
5320
|
const folder2 = leaseFolder(this.dir, accountId);
|
|
5093
5321
|
mkdirSync9(folder2, { recursive: true, mode: 448 });
|
|
5094
|
-
atomicWrite(
|
|
5322
|
+
atomicWrite(join21(folder2, String(process.pid)), JSON.stringify({ pid: process.pid, startedAt: now() }));
|
|
5095
5323
|
}
|
|
5096
5324
|
releaseLease(accountId) {
|
|
5097
|
-
rmSync7(
|
|
5325
|
+
rmSync7(join21(leaseFolder(this.dir, accountId), String(process.pid)), { force: true });
|
|
5098
5326
|
}
|
|
5099
5327
|
// ---- Health from runs ---------------------------------------------------------------------
|
|
5100
5328
|
/** Tracks account health and limits from run events. `run` is the event's run record, when it is known. */
|
|
@@ -5116,17 +5344,17 @@ var Accounts = class {
|
|
|
5116
5344
|
*/
|
|
5117
5345
|
applyLimits(accountId, readouts) {
|
|
5118
5346
|
this.find(accountId);
|
|
5119
|
-
const expired = (
|
|
5120
|
-
const time =
|
|
5347
|
+
const expired = (limit2) => {
|
|
5348
|
+
const time = limit2.resetsAt ? Date.parse(limit2.resetsAt) : Number.NaN;
|
|
5121
5349
|
return !Number.isNaN(time) && time <= Date.now();
|
|
5122
5350
|
};
|
|
5123
5351
|
updateState(this.dir, accountId, (state) => {
|
|
5124
5352
|
for (const readout of readouts) {
|
|
5125
5353
|
const kept = new Map(
|
|
5126
|
-
(readout.source === "provider" ? [] : state.limits.filter((
|
|
5354
|
+
(readout.source === "provider" ? [] : state.limits.filter((limit2) => limit2.provider === readout.provider && !expired(limit2))).map((limit2) => [limit2.id, limit2])
|
|
5127
5355
|
);
|
|
5128
|
-
for (const
|
|
5129
|
-
state.limits = [...state.limits.filter((
|
|
5356
|
+
for (const limit2 of readout.limits) kept.set(limit2.id, limit2);
|
|
5357
|
+
state.limits = [...state.limits.filter((limit2) => limit2.provider !== readout.provider), ...kept.values()];
|
|
5130
5358
|
const entry2 = { provider: readout.provider, source: readout.source, reason: readout.reason, observedAt: readout.observedAt };
|
|
5131
5359
|
state.providerLimits = [...state.providerLimits.filter((existing) => existing.provider !== readout.provider), entry2];
|
|
5132
5360
|
if (readout.plan) state.plan = readout.plan;
|
|
@@ -5148,7 +5376,7 @@ var Accounts = class {
|
|
|
5148
5376
|
try {
|
|
5149
5377
|
result = updateState(this.dir, accountId, (state) => {
|
|
5150
5378
|
if (limits) {
|
|
5151
|
-
for (const
|
|
5379
|
+
for (const limit2 of limits) state.limits = [...state.limits.filter((existing) => existing.id !== limit2.id), limit2];
|
|
5152
5380
|
state.limits.sort((left, right) => left.id < right.id ? -1 : left.id > right.id ? 1 : 0);
|
|
5153
5381
|
}
|
|
5154
5382
|
if (text10(payload2.plan) !== null) state.plan = text10(payload2.plan);
|
|
@@ -5173,7 +5401,7 @@ var Accounts = class {
|
|
|
5173
5401
|
init_errors();
|
|
5174
5402
|
init_fs();
|
|
5175
5403
|
import { createHash as createHash8 } from "node:crypto";
|
|
5176
|
-
import { closeSync as closeSync3, lstatSync as lstatSync8, mkdirSync as mkdirSync18, mkdtempSync as mkdtempSync4, openSync as openSync3, readFileSync as
|
|
5404
|
+
import { closeSync as closeSync3, lstatSync as lstatSync8, mkdirSync as mkdirSync18, mkdtempSync as mkdtempSync4, openSync as openSync3, readFileSync as readFileSync23, renameSync as renameSync8, rmSync as rmSync17, writeFileSync as writeFileSync8 } from "node:fs";
|
|
5177
5405
|
import { join as join44 } from "node:path";
|
|
5178
5406
|
import { watch } from "node:fs";
|
|
5179
5407
|
|
|
@@ -5183,9 +5411,9 @@ init_errors();
|
|
|
5183
5411
|
|
|
5184
5412
|
// src/plugins/attachments.ts
|
|
5185
5413
|
init_fs();
|
|
5186
|
-
import { join as
|
|
5187
|
-
var path2 = (root) =>
|
|
5188
|
-
var legacyPath = (root) =>
|
|
5414
|
+
import { join as join22 } from "node:path";
|
|
5415
|
+
var path2 = (root) => join22(root, "config/plugin-attachments.json");
|
|
5416
|
+
var legacyPath = (root) => join22(root, "config/registry-enabled.json");
|
|
5189
5417
|
var strings2 = (value) => Array.isArray(value) ? value.filter((id) => typeof id === "string") : [];
|
|
5190
5418
|
var entries = (value) => {
|
|
5191
5419
|
const record3 = value && typeof value === "object" ? value : {};
|
|
@@ -5265,7 +5493,7 @@ function forgetId(attachments, id) {
|
|
|
5265
5493
|
}
|
|
5266
5494
|
|
|
5267
5495
|
// src/plugins/catalogue.ts
|
|
5268
|
-
import { basename as basename7, dirname as
|
|
5496
|
+
import { basename as basename7, dirname as dirname11 } from "node:path";
|
|
5269
5497
|
|
|
5270
5498
|
// src/plugins/firstParty.ts
|
|
5271
5499
|
var OUTPUT_TRIM = "output-trim";
|
|
@@ -5378,13 +5606,13 @@ function firstPartyExtensions(on, settings) {
|
|
|
5378
5606
|
}
|
|
5379
5607
|
|
|
5380
5608
|
// src/plugins/discover.ts
|
|
5381
|
-
import { existsSync as
|
|
5609
|
+
import { existsSync as existsSync11, lstatSync as lstatSync3, readdirSync as readdirSync12, readFileSync as readFileSync13 } from "node:fs";
|
|
5382
5610
|
import { homedir as homedir2 } from "node:os";
|
|
5383
|
-
import { join as
|
|
5611
|
+
import { join as join24, sep as sep5 } from "node:path";
|
|
5384
5612
|
|
|
5385
5613
|
// src/plugins/manifest.ts
|
|
5386
5614
|
init_fs();
|
|
5387
|
-
import { basename as basename4, join as
|
|
5615
|
+
import { basename as basename4, join as join23 } from "node:path";
|
|
5388
5616
|
import { z as z2 } from "zod";
|
|
5389
5617
|
var connectorTemplateSchema = z2.object({
|
|
5390
5618
|
id: z2.string().regex(/^[a-z0-9-]+$/),
|
|
@@ -5421,13 +5649,13 @@ var PLUGIN_MANIFESTS = ["plugin.json", ".claude-plugin/plugin.json", ".codex-plu
|
|
|
5421
5649
|
var text3 = (value) => typeof value === "string" && value.trim() ? value.trim() : null;
|
|
5422
5650
|
function pluginJson(packageRoot) {
|
|
5423
5651
|
for (const file2 of PLUGIN_MANIFESTS) {
|
|
5424
|
-
const found = readJsonOr(
|
|
5652
|
+
const found = readJsonOr(join23(packageRoot, file2), null);
|
|
5425
5653
|
if (found && typeof found === "object" && !Array.isArray(found)) return found;
|
|
5426
5654
|
}
|
|
5427
5655
|
return {};
|
|
5428
5656
|
}
|
|
5429
5657
|
function packageManifest(packageRoot) {
|
|
5430
|
-
const manifest = readJsonOr(
|
|
5658
|
+
const manifest = readJsonOr(join23(packageRoot, "package.json"), {});
|
|
5431
5659
|
const plugin = text3(manifest.name) ? {} : pluginJson(packageRoot);
|
|
5432
5660
|
const own = manifest.harness && typeof manifest.harness === "object" && !Array.isArray(manifest.harness) ? manifest.harness : {};
|
|
5433
5661
|
const pluginName = text3(plugin.name);
|
|
@@ -5451,20 +5679,20 @@ var PI_BUILTINS = ["llama.cpp", "codemode", "tool-search", "mcp"];
|
|
|
5451
5679
|
var BUILTIN_PREFIX = "builtin:";
|
|
5452
5680
|
var MAX_PACKAGE_PROFILES = 50;
|
|
5453
5681
|
function packageProfiles(root, folder2) {
|
|
5454
|
-
const dir2 =
|
|
5682
|
+
const dir2 = join24(root, folder2);
|
|
5455
5683
|
let names2;
|
|
5456
5684
|
try {
|
|
5457
5685
|
if (!lstatSync3(dir2).isDirectory()) return [];
|
|
5458
|
-
names2 =
|
|
5686
|
+
names2 = readdirSync12(dir2).filter((name) => name.endsWith(".md") && !name.startsWith(".")).sort();
|
|
5459
5687
|
} catch {
|
|
5460
5688
|
return [];
|
|
5461
5689
|
}
|
|
5462
5690
|
const profiles = [];
|
|
5463
5691
|
for (const name of names2) {
|
|
5464
|
-
const path4 =
|
|
5692
|
+
const path4 = join24(dir2, name);
|
|
5465
5693
|
try {
|
|
5466
5694
|
if (!lstatSync3(path4).isFile()) continue;
|
|
5467
|
-
const front = parse(
|
|
5695
|
+
const front = parse(readFileSync13(path4, "utf8"))?.front;
|
|
5468
5696
|
if (typeof front?.name === "string" && front.name.trim() && typeof front.description === "string" && front.description.trim()) profiles.push(path4);
|
|
5469
5697
|
} catch {
|
|
5470
5698
|
continue;
|
|
@@ -5478,7 +5706,7 @@ function origin(path4, metadata) {
|
|
|
5478
5706
|
if (path4.startsWith(BUILTIN_PREFIX)) return "builtin";
|
|
5479
5707
|
if (metadata.origin === "package") return "package";
|
|
5480
5708
|
if (metadata.scope === "project") return "project";
|
|
5481
|
-
return metadata.baseDir && inside3(metadata.baseDir,
|
|
5709
|
+
return metadata.baseDir && inside3(metadata.baseDir, join24(process.env.HOME || homedir2(), ".agents")) ? "home" : "shared";
|
|
5482
5710
|
}
|
|
5483
5711
|
async function withoutInstallScripts(action) {
|
|
5484
5712
|
const before = process.env.npm_config_ignore_scripts;
|
|
@@ -5538,14 +5766,14 @@ var piResolver = async ({ cwd, agentDir, install: install3, packages }) => {
|
|
|
5538
5766
|
const manifest = packageManifest(root);
|
|
5539
5767
|
for (const path4 of packageProfiles(root, manifest.agents)) found.push({ kind: "agent", path: path4, origin: "package", project: false, packageRoot: root, source, enabled: true });
|
|
5540
5768
|
const hooks = manifest.hooks;
|
|
5541
|
-
if (!hooks || !
|
|
5542
|
-
found.push({ kind: "hook", path:
|
|
5769
|
+
if (!hooks || !existsSync11(join24(root, hooks))) continue;
|
|
5770
|
+
found.push({ kind: "hook", path: join24(root, hooks), origin: "package", project: false, packageRoot: root, source, enabled: true });
|
|
5543
5771
|
const fallback = found.findIndex((item) => item.kind === "extension" && item.path === root);
|
|
5544
5772
|
if (fallback !== -1) found.splice(fallback, 1);
|
|
5545
5773
|
}
|
|
5546
5774
|
const context = [
|
|
5547
5775
|
...pi.loadProjectContextFiles({ cwd, agentDir }).map((file2) => file2.path),
|
|
5548
|
-
...[
|
|
5776
|
+
...[join24(agentDir, "SYSTEM.md"), join24(agentDir, "APPEND_SYSTEM.md"), join24(cwd, ".pi", "SYSTEM.md"), join24(cwd, ".pi", "APPEND_SYSTEM.md")].filter((path4) => existsSync11(path4))
|
|
5549
5777
|
];
|
|
5550
5778
|
for (const path4 of context) {
|
|
5551
5779
|
const shared2 = inside3(path4, agentDir);
|
|
@@ -5556,12 +5784,12 @@ var piResolver = async ({ cwd, agentDir, install: install3, packages }) => {
|
|
|
5556
5784
|
|
|
5557
5785
|
// src/plugins/runtime.ts
|
|
5558
5786
|
import { createHash as createHash3 } from "node:crypto";
|
|
5559
|
-
import { readFileSync as
|
|
5560
|
-
import { dirname as
|
|
5787
|
+
import { readFileSync as readFileSync15, readdirSync as readdirSync13, statSync as statSync8 } from "node:fs";
|
|
5788
|
+
import { dirname as dirname9, resolve as resolve4 } from "node:path";
|
|
5561
5789
|
|
|
5562
5790
|
// src/plugins/identity.ts
|
|
5563
|
-
import { readFileSync as
|
|
5564
|
-
import { basename as basename5, dirname as
|
|
5791
|
+
import { readFileSync as readFileSync14 } from "node:fs";
|
|
5792
|
+
import { basename as basename5, dirname as dirname8 } from "node:path";
|
|
5565
5793
|
var FOUND_KINDS = { extension: "code", hook: "code", skill: "skill", prompt: "command", agent: "agent", theme: "theme", context: "instruction" };
|
|
5566
5794
|
function pluginIdOf(item) {
|
|
5567
5795
|
if (item.origin === "builtin") return "pi";
|
|
@@ -5571,7 +5799,7 @@ function pluginIdOf(item) {
|
|
|
5571
5799
|
function describeFound(item) {
|
|
5572
5800
|
if (item.path.startsWith(BUILTIN_PREFIX)) return { name: item.path.slice(BUILTIN_PREFIX.length), description: null };
|
|
5573
5801
|
const file2 = basename5(item.path);
|
|
5574
|
-
if (item.kind === "extension") return { name: file2.startsWith("index.") ? basename5(
|
|
5802
|
+
if (item.kind === "extension") return { name: file2.startsWith("index.") ? basename5(dirname8(item.path)) : file2, description: null };
|
|
5575
5803
|
if (item.kind === "context" || item.kind === "theme" || item.kind === "hook") return { name: file2, description: null };
|
|
5576
5804
|
const described = describeFile(item.path);
|
|
5577
5805
|
return { name: described?.name ?? file2, description: described?.description ?? "" };
|
|
@@ -5584,12 +5812,12 @@ function foundIds(item) {
|
|
|
5584
5812
|
function describeFile(path4) {
|
|
5585
5813
|
let text10;
|
|
5586
5814
|
try {
|
|
5587
|
-
text10 =
|
|
5815
|
+
text10 = readFileSync14(path4, "utf8");
|
|
5588
5816
|
} catch {
|
|
5589
5817
|
return null;
|
|
5590
5818
|
}
|
|
5591
5819
|
const front = parse(text10)?.front ?? {};
|
|
5592
|
-
const fallback = basename5(path4) === "SKILL.md" ? basename5(
|
|
5820
|
+
const fallback = basename5(path4) === "SKILL.md" ? basename5(dirname8(path4)) : basename5(path4).replace(/\.md$/, "");
|
|
5593
5821
|
return { name: typeof front.name === "string" && front.name.trim() ? front.name.trim() : fallback, description: typeof front.description === "string" ? front.description.trim() : "" };
|
|
5594
5822
|
}
|
|
5595
5823
|
|
|
@@ -5602,7 +5830,7 @@ function registrationHash(loading, path4) {
|
|
|
5602
5830
|
if (owner?.project) return loading.projectCode?.hash ?? null;
|
|
5603
5831
|
if (owner?.packageRoot) return loading.packageCode[owner.packageRoot]?.hash ?? null;
|
|
5604
5832
|
try {
|
|
5605
|
-
return createHash3("sha256").update(
|
|
5833
|
+
return createHash3("sha256").update(readFileSync15(path4)).digest("hex");
|
|
5606
5834
|
} catch {
|
|
5607
5835
|
return null;
|
|
5608
5836
|
}
|
|
@@ -5612,7 +5840,7 @@ function resourceOf(owner, kind, path4) {
|
|
|
5612
5840
|
const described = describeFound(found);
|
|
5613
5841
|
let chars = null;
|
|
5614
5842
|
try {
|
|
5615
|
-
chars = charCount(
|
|
5843
|
+
chars = charCount(readFileSync15(path4, "utf8"));
|
|
5616
5844
|
} catch {
|
|
5617
5845
|
}
|
|
5618
5846
|
return { kind: FOUND_KINDS[kind], name: described.name, path: path4, chars };
|
|
@@ -5641,17 +5869,17 @@ function observeResources(pi, loader, loading, records, publish) {
|
|
|
5641
5869
|
collected.push(resource);
|
|
5642
5870
|
return loading.resourceAllowed?.({ ...owner, kind, path: resourcePath }) !== false;
|
|
5643
5871
|
};
|
|
5644
|
-
const absolute2 = (entry2) => resolve4(
|
|
5645
|
-
const skills = pi.loadSkills({ cwd:
|
|
5646
|
-
const scanner = new pi.DefaultResourceLoader({ cwd:
|
|
5872
|
+
const absolute2 = (entry2) => resolve4(dirname9(path4), entry2);
|
|
5873
|
+
const skills = pi.loadSkills({ cwd: dirname9(path4), agentDir: dirname9(path4), includeDefaults: false, skillPaths: (result.skillPaths ?? []).map(absolute2) }).skills;
|
|
5874
|
+
const scanner = new pi.DefaultResourceLoader({ cwd: dirname9(path4), agentDir: dirname9(path4), settingsManager: pi.SettingsManager.inMemory({}), noExtensions: true, noSkills: true, noThemes: true, noContextFiles: true, noPromptTemplates: true, additionalPromptTemplatePaths: (result.promptPaths ?? []).map(absolute2) });
|
|
5647
5875
|
await scanner.reload();
|
|
5648
5876
|
const prompts = scanner.getPrompts().prompts;
|
|
5649
5877
|
const themes = (result.themePaths ?? []).map(absolute2).flatMap((theme) => {
|
|
5650
5878
|
try {
|
|
5651
|
-
if (
|
|
5879
|
+
if (statSync8(theme).isDirectory()) return readdirSync13(theme).filter((name) => {
|
|
5652
5880
|
if (!name.endsWith(".json")) return false;
|
|
5653
5881
|
try {
|
|
5654
|
-
return
|
|
5882
|
+
return statSync8(resolve4(theme, name)).isFile();
|
|
5655
5883
|
} catch {
|
|
5656
5884
|
return false;
|
|
5657
5885
|
}
|
|
@@ -5675,14 +5903,14 @@ function observeResources(pi, loader, loading, records, publish) {
|
|
|
5675
5903
|
|
|
5676
5904
|
// src/plugins/plugins.ts
|
|
5677
5905
|
init_fs();
|
|
5678
|
-
import { chmodSync as chmodSync5, lstatSync as lstatSync5, readdirSync as
|
|
5679
|
-
import { join as
|
|
5906
|
+
import { chmodSync as chmodSync5, lstatSync as lstatSync5, readdirSync as readdirSync15, rmSync as rmSync8, unlinkSync as unlinkSync3 } from "node:fs";
|
|
5907
|
+
import { join as join26 } from "node:path";
|
|
5680
5908
|
|
|
5681
5909
|
// src/plugins/trust.ts
|
|
5682
5910
|
init_fs();
|
|
5683
5911
|
import { createHash as createHash4 } from "node:crypto";
|
|
5684
|
-
import { chmodSync as chmodSync4, lstatSync as lstatSync4, readdirSync as
|
|
5685
|
-
import { basename as basename6, dirname as
|
|
5912
|
+
import { chmodSync as chmodSync4, lstatSync as lstatSync4, readdirSync as readdirSync14, readFileSync as readFileSync16 } from "node:fs";
|
|
5913
|
+
import { basename as basename6, dirname as dirname10, join as join25, relative as relative4, sep as sep6 } from "node:path";
|
|
5686
5914
|
var SKIPPED = /* @__PURE__ */ new Set(["node_modules", ".git"]);
|
|
5687
5915
|
var MAX_FILES = 5e3;
|
|
5688
5916
|
function walk3(path4, into) {
|
|
@@ -5699,9 +5927,9 @@ function walk3(path4, into) {
|
|
|
5699
5927
|
return;
|
|
5700
5928
|
}
|
|
5701
5929
|
if (!meta.isDirectory()) return;
|
|
5702
|
-
for (const name of
|
|
5930
|
+
for (const name of readdirSync14(path4).sort(compareText)) if (!SKIPPED.has(name)) walk3(join25(path4, name), into);
|
|
5703
5931
|
}
|
|
5704
|
-
var unit = (item) => item.packageRoot ?? (basename6(item.path).startsWith("index.") ?
|
|
5932
|
+
var unit = (item) => item.packageRoot ?? (basename6(item.path).startsWith("index.") ? dirname10(item.path) : item.path);
|
|
5705
5933
|
function hashOf(units, base) {
|
|
5706
5934
|
const paths2 = [];
|
|
5707
5935
|
for (const path4 of [...units].sort(compareText)) walk3(path4, paths2);
|
|
@@ -5714,7 +5942,7 @@ function hashOf(units, base) {
|
|
|
5714
5942
|
for (const path4 of [...new Set(paths2)].sort(compareText)) {
|
|
5715
5943
|
let contents;
|
|
5716
5944
|
try {
|
|
5717
|
-
contents =
|
|
5945
|
+
contents = readFileSync16(path4);
|
|
5718
5946
|
} catch {
|
|
5719
5947
|
continue;
|
|
5720
5948
|
}
|
|
@@ -5734,7 +5962,7 @@ function packageCode(found) {
|
|
|
5734
5962
|
var Trust = class {
|
|
5735
5963
|
constructor(stateDir, bus) {
|
|
5736
5964
|
this.bus = bus;
|
|
5737
|
-
this.path =
|
|
5965
|
+
this.path = join25(stateDir, "plugin-trust.json");
|
|
5738
5966
|
}
|
|
5739
5967
|
bus;
|
|
5740
5968
|
path;
|
|
@@ -5779,7 +6007,7 @@ var Trust = class {
|
|
|
5779
6007
|
function packageFolders(directory) {
|
|
5780
6008
|
if (!directory) return [];
|
|
5781
6009
|
try {
|
|
5782
|
-
return
|
|
6010
|
+
return readdirSync15(directory, { withFileTypes: true }).filter((entry2) => entry2.isDirectory() && !entry2.name.startsWith(".")).map((entry2) => join26(directory, entry2.name)).sort();
|
|
5783
6011
|
} catch {
|
|
5784
6012
|
return [];
|
|
5785
6013
|
}
|
|
@@ -5802,7 +6030,7 @@ var Plugins = class {
|
|
|
5802
6030
|
this.options = options2;
|
|
5803
6031
|
this.trust = new Trust(options2.stateDir, options2.bus);
|
|
5804
6032
|
this.resolver = options2.resolver ?? piResolver;
|
|
5805
|
-
this.registeredPath =
|
|
6033
|
+
this.registeredPath = join26(options2.stateDir, "plugin-registered.json");
|
|
5806
6034
|
}
|
|
5807
6035
|
options;
|
|
5808
6036
|
trust;
|
|
@@ -5810,7 +6038,7 @@ var Plugins = class {
|
|
|
5810
6038
|
registeredPath;
|
|
5811
6039
|
/** Finds what Pi would load in this folder, and chooses what does. */
|
|
5812
6040
|
async loading(input) {
|
|
5813
|
-
removeLinkedSkills(
|
|
6041
|
+
removeLinkedSkills(join26(input.agentDir, "skills"));
|
|
5814
6042
|
const found = await this.resolver({ ...input, packages: packageFolders(this.options.packagesDir?.() ?? null) });
|
|
5815
6043
|
const code = projectCode(found, input.cwd);
|
|
5816
6044
|
const packages = packageCode(found);
|
|
@@ -5876,8 +6104,8 @@ function isLinkedSkill(path4) {
|
|
|
5876
6104
|
if (meta.isSymbolicLink()) return true;
|
|
5877
6105
|
if (!meta.isDirectory()) return false;
|
|
5878
6106
|
try {
|
|
5879
|
-
const entries2 =
|
|
5880
|
-
return entries2.length === 1 && entries2[0] === "SKILL.md" && lstatSync5(
|
|
6107
|
+
const entries2 = readdirSync15(path4);
|
|
6108
|
+
return entries2.length === 1 && entries2[0] === "SKILL.md" && lstatSync5(join26(path4, "SKILL.md")).isSymbolicLink();
|
|
5881
6109
|
} catch {
|
|
5882
6110
|
return false;
|
|
5883
6111
|
}
|
|
@@ -5885,12 +6113,12 @@ function isLinkedSkill(path4) {
|
|
|
5885
6113
|
function removeLinkedSkills(skillsDir) {
|
|
5886
6114
|
let names2;
|
|
5887
6115
|
try {
|
|
5888
|
-
names2 =
|
|
6116
|
+
names2 = readdirSync15(skillsDir);
|
|
5889
6117
|
} catch {
|
|
5890
6118
|
return;
|
|
5891
6119
|
}
|
|
5892
6120
|
for (const name of names2) {
|
|
5893
|
-
const path4 =
|
|
6121
|
+
const path4 = join26(skillsDir, name);
|
|
5894
6122
|
if (!name.startsWith(LINKED_SKILL_PREFIX) || !isLinkedSkill(path4)) continue;
|
|
5895
6123
|
if (lstatSync5(path4).isSymbolicLink()) unlinkSync3(path4);
|
|
5896
6124
|
else rmSync8(path4, { recursive: true, force: true });
|
|
@@ -6024,7 +6252,7 @@ function catalogue(input) {
|
|
|
6024
6252
|
const install3 = item.project ? null : item.packageRoot.startsWith(`${input.packagesDir}/`) ? { kind: "folder", source: item.packageRoot } : item.source ? { kind: "settings", source: item.source } : null;
|
|
6025
6253
|
const extended = manifest.extends.filter((part) => input.descriptors.some((descriptor) => descriptor.id === part));
|
|
6026
6254
|
plugin = { ...empty(id, manifest.name, manifest.description, item.project ? "project" : "package", item.packageRoot), version: manifest.version, install: install3, extends: extended, connectorTemplates: manifest.connectorTemplates };
|
|
6027
|
-
} else if (item.origin === "home") plugin = empty(id, "Home folder skills", "Skills in the .agents folder of your home folder. Pi reads them for every account.", "home",
|
|
6255
|
+
} else if (item.origin === "home") plugin = empty(id, "Home folder skills", "Skills in the .agents folder of your home folder. Pi reads them for every account.", "home", dirname11(dirname11(item.path)));
|
|
6028
6256
|
else if (item.origin === "project") plugin = empty(id, "Project folder", "Found in the working folder: its .pi and .agents folders, and the instruction files Pi reads on the way up from it.", "project", input.cwd);
|
|
6029
6257
|
else plugin = empty(id, "Shared Pi folder", "Extensions, skills, prompts and instruction files in the folder every account shares.", "shared", input.sharedDir);
|
|
6030
6258
|
plugin.attachment = describe(input.attachments, id, true);
|
|
@@ -6061,19 +6289,19 @@ function catalogue(input) {
|
|
|
6061
6289
|
}
|
|
6062
6290
|
|
|
6063
6291
|
// src/plugins/inventory.ts
|
|
6064
|
-
import { readFileSync as
|
|
6292
|
+
import { readFileSync as readFileSync21 } from "node:fs";
|
|
6065
6293
|
|
|
6066
6294
|
// src/mcp/connections.ts
|
|
6067
6295
|
import { chmodSync as chmodSync7 } from "node:fs";
|
|
6068
|
-
import { isAbsolute as isAbsolute4, join as
|
|
6296
|
+
import { isAbsolute as isAbsolute4, join as join29 } from "node:path";
|
|
6069
6297
|
init_errors();
|
|
6070
6298
|
init_fs();
|
|
6071
6299
|
|
|
6072
6300
|
// src/core/path.ts
|
|
6073
6301
|
import { execFileSync } from "node:child_process";
|
|
6074
|
-
import { accessSync, constants, statSync as
|
|
6302
|
+
import { accessSync, constants, statSync as statSync9 } from "node:fs";
|
|
6075
6303
|
import { homedir as homedir3 } from "node:os";
|
|
6076
|
-
import { delimiter, extname, isAbsolute as isAbsolute3, join as
|
|
6304
|
+
import { delimiter, extname, isAbsolute as isAbsolute3, join as join27 } from "node:path";
|
|
6077
6305
|
var resolved = null;
|
|
6078
6306
|
function searchPath() {
|
|
6079
6307
|
const platform = process.platform;
|
|
@@ -6092,7 +6320,7 @@ function searchPath() {
|
|
|
6092
6320
|
entries2.push(...inherited.split(separator));
|
|
6093
6321
|
if (platform !== "win32") {
|
|
6094
6322
|
const home = homedir3();
|
|
6095
|
-
if (home) entries2.push(...[".local/bin", ".bun/bin", ".npm-global/bin", ".cargo/bin"].map((folder2) =>
|
|
6323
|
+
if (home) entries2.push(...[".local/bin", ".bun/bin", ".npm-global/bin", ".cargo/bin"].map((folder2) => join27(home, folder2)));
|
|
6096
6324
|
entries2.push("/opt/homebrew/bin", "/usr/local/bin", "/usr/bin", "/bin");
|
|
6097
6325
|
}
|
|
6098
6326
|
const path4 = [...new Set(entries2.filter(Boolean))].join(separator);
|
|
@@ -6112,7 +6340,7 @@ function pathSeparator(platform) {
|
|
|
6112
6340
|
function isExecutable(path4) {
|
|
6113
6341
|
try {
|
|
6114
6342
|
accessSync(path4, process.platform === "win32" ? constants.F_OK : constants.X_OK);
|
|
6115
|
-
return
|
|
6343
|
+
return statSync9(path4).isFile();
|
|
6116
6344
|
} catch {
|
|
6117
6345
|
return false;
|
|
6118
6346
|
}
|
|
@@ -6127,7 +6355,7 @@ function findBinary(name) {
|
|
|
6127
6355
|
}
|
|
6128
6356
|
for (const directory of searchPath().split(pathSeparator(platform))) {
|
|
6129
6357
|
for (const candidateName of names2) {
|
|
6130
|
-
const candidate =
|
|
6358
|
+
const candidate = join27(directory, candidateName);
|
|
6131
6359
|
if (isExecutable(candidate)) return candidate;
|
|
6132
6360
|
}
|
|
6133
6361
|
}
|
|
@@ -6139,8 +6367,8 @@ init_fs();
|
|
|
6139
6367
|
|
|
6140
6368
|
// src/mcp/scopeMigration.ts
|
|
6141
6369
|
init_fs();
|
|
6142
|
-
import { chmodSync as chmodSync6, existsSync as
|
|
6143
|
-
import { join as
|
|
6370
|
+
import { chmodSync as chmodSync6, existsSync as existsSync12, readFileSync as readFileSync17, unlinkSync as unlinkSync4 } from "node:fs";
|
|
6371
|
+
import { join as join28 } from "node:path";
|
|
6144
6372
|
|
|
6145
6373
|
// src/mcp/types.ts
|
|
6146
6374
|
import { z as z3 } from "zod";
|
|
@@ -6189,11 +6417,11 @@ var connectionInputSchema = connectionSchema.extend({
|
|
|
6189
6417
|
});
|
|
6190
6418
|
|
|
6191
6419
|
// src/mcp/scopeMigration.ts
|
|
6192
|
-
var recordPath2 = (root) =>
|
|
6193
|
-
var attachmentsPath = (root) =>
|
|
6194
|
-
var connectionPath = (stateDir) =>
|
|
6195
|
-
var connectionsBackupPath = (stateDir) =>
|
|
6196
|
-
var attachmentsBackupPath = (root) =>
|
|
6420
|
+
var recordPath2 = (root) => join28(root, "config/capability-scope-migration.json");
|
|
6421
|
+
var attachmentsPath = (root) => join28(root, "config/plugin-attachments.json");
|
|
6422
|
+
var connectionPath = (stateDir) => join28(stateDir, "connections.json");
|
|
6423
|
+
var connectionsBackupPath = (stateDir) => join28(stateDir, "connections.pre-capability-scope.json");
|
|
6424
|
+
var attachmentsBackupPath = (root) => join28(root, "config/plugin-attachments.pre-capability-scope.json");
|
|
6197
6425
|
function connectionScopeMigrationComplete(root) {
|
|
6198
6426
|
try {
|
|
6199
6427
|
const marker = readJson(recordPath2(root));
|
|
@@ -6255,8 +6483,8 @@ function verifyRows(choices, id, expected) {
|
|
|
6255
6483
|
return true;
|
|
6256
6484
|
}
|
|
6257
6485
|
function backup(source, target) {
|
|
6258
|
-
if (!
|
|
6259
|
-
if (!
|
|
6486
|
+
if (!existsSync12(source)) return false;
|
|
6487
|
+
if (!existsSync12(target)) atomicWrite(target, readFileSync17(source));
|
|
6260
6488
|
chmodSync6(target, 384);
|
|
6261
6489
|
return true;
|
|
6262
6490
|
}
|
|
@@ -6268,7 +6496,7 @@ function setPrivate(path4) {
|
|
|
6268
6496
|
}
|
|
6269
6497
|
function stripScopes(stateDir) {
|
|
6270
6498
|
const path4 = connectionPath(stateDir);
|
|
6271
|
-
if (!
|
|
6499
|
+
if (!existsSync12(path4)) return;
|
|
6272
6500
|
const stored = readJson(path4);
|
|
6273
6501
|
if (!Array.isArray(stored)) throw new Error("Stored connector data must be a list before its scopes can be migrated.");
|
|
6274
6502
|
const records = stored.map((item) => {
|
|
@@ -6289,7 +6517,7 @@ function migrateConnectionScopes(root, stateDir) {
|
|
|
6289
6517
|
return complete;
|
|
6290
6518
|
}
|
|
6291
6519
|
const connectionsFile = connectionPath(stateDir);
|
|
6292
|
-
const hadConnections =
|
|
6520
|
+
const hadConnections = existsSync12(connectionsFile);
|
|
6293
6521
|
const raw = hadConnections ? readJson(connectionsFile) : [];
|
|
6294
6522
|
if (!Array.isArray(raw)) throw new Error("Stored connector data must be a list before its scopes can be migrated.");
|
|
6295
6523
|
const parsed = raw.map((item) => {
|
|
@@ -6298,7 +6526,7 @@ function migrateConnectionScopes(root, stateDir) {
|
|
|
6298
6526
|
return result.data;
|
|
6299
6527
|
});
|
|
6300
6528
|
const connectionBackup = hadConnections ? connectionsBackupPath(stateDir) : null;
|
|
6301
|
-
const hadAttachments =
|
|
6529
|
+
const hadAttachments = existsSync12(attachmentsPath(root));
|
|
6302
6530
|
const attachmentBackup = hadAttachments ? attachmentsBackupPath(root) : null;
|
|
6303
6531
|
const migration = {
|
|
6304
6532
|
version: 1,
|
|
@@ -6333,9 +6561,9 @@ function migrateConnectionScopes(root, stateDir) {
|
|
|
6333
6561
|
writeJson(recordPath2(root), complete);
|
|
6334
6562
|
return complete;
|
|
6335
6563
|
} catch (error) {
|
|
6336
|
-
if (attachmentBackup &&
|
|
6337
|
-
else if (!hadAttachments &&
|
|
6338
|
-
if (connectionBackup &&
|
|
6564
|
+
if (attachmentBackup && existsSync12(attachmentBackup)) atomicWrite(attachmentsPath(root), readFileSync17(attachmentBackup));
|
|
6565
|
+
else if (!hadAttachments && existsSync12(attachmentsPath(root))) unlinkSync4(attachmentsPath(root));
|
|
6566
|
+
if (connectionBackup && existsSync12(connectionBackup)) atomicWrite(connectionsFile, readFileSync17(connectionBackup));
|
|
6339
6567
|
try {
|
|
6340
6568
|
unlinkSync4(recordPath2(root));
|
|
6341
6569
|
} catch {
|
|
@@ -6464,7 +6692,7 @@ var Connections = class {
|
|
|
6464
6692
|
this.bus = bus;
|
|
6465
6693
|
this.attachmentRoot = attachmentRoot;
|
|
6466
6694
|
this.appClients = appClients;
|
|
6467
|
-
this.path =
|
|
6695
|
+
this.path = join29(stateDir, "connections.json");
|
|
6468
6696
|
}
|
|
6469
6697
|
secrets;
|
|
6470
6698
|
bus;
|
|
@@ -7175,10 +7403,10 @@ function canonical(value, depth2 = 0) {
|
|
|
7175
7403
|
return `{${entries2.map(([key, item]) => `${JSON.stringify(key)}:${canonical(item, depth2 + 1)}`).join(",")}}`;
|
|
7176
7404
|
}
|
|
7177
7405
|
var signature = (name, input) => `${name}\0${createHash5("sha256").update(canonical(input ?? null)).digest("hex")}`;
|
|
7178
|
-
var clip2 = (value,
|
|
7179
|
-
function handoffRequest(
|
|
7406
|
+
var clip2 = (value, limit2) => value.length <= limit2 ? value : `${value.slice(0, limit2 - 1)}\u2026`;
|
|
7407
|
+
function handoffRequest(limit2, state, checkpointAvailable = true) {
|
|
7180
7408
|
const handoff = checkpointAvailable ? "Call checkpoint_write now with what is done, the single next step, anything blocking, the files you touched and the checks that matter. Then tell the user in a few lines where you stopped." : "Stop using tools and return a concise partial research report with findings, blockers and the next useful research step. The Harness records an evidence-derived checkpoint.";
|
|
7181
|
-
return clip2(`This reply reached its work-slice limit (${
|
|
7409
|
+
return clip2(`This reply reached its work-slice limit (${limit2}; step ${state.steps}). ${handoff} Do not call other tools.`, 600);
|
|
7182
7410
|
}
|
|
7183
7411
|
function stalledNote(reason, checkpointAvailable = true) {
|
|
7184
7412
|
const handoff = checkpointAvailable ? "Choose a different approach, read what the earlier attempt returned, or call checkpoint_write with the blocker so the next slice can decide." : "Do not use more tools. Return concise findings and blockers in your final response; the Harness records an evidence-derived checkpoint.";
|
|
@@ -7199,12 +7427,12 @@ function workSliceGuard(options2) {
|
|
|
7199
7427
|
failures.clear();
|
|
7200
7428
|
nudged = false;
|
|
7201
7429
|
};
|
|
7202
|
-
const end = (kind,
|
|
7430
|
+
const end = (kind, limit2) => {
|
|
7203
7431
|
state.endedBy = kind;
|
|
7204
|
-
state.endedByLimit =
|
|
7205
|
-
options2.onEnd?.(kind,
|
|
7432
|
+
state.endedByLimit = limit2;
|
|
7433
|
+
options2.onEnd?.(kind, limit2);
|
|
7206
7434
|
const canCheckpoint = checkpointAvailable();
|
|
7207
|
-
const reason = kind === "stuck" ? stalledNote(
|
|
7435
|
+
const reason = kind === "stuck" ? stalledNote(limit2, canCheckpoint) : kind === "compaction-thrash" ? handoffRequest("three context compactions in one reply", state, canCheckpoint) : handoffRequest(limit2, state, canCheckpoint);
|
|
7208
7436
|
return { block: true, terminate: true, reason };
|
|
7209
7437
|
};
|
|
7210
7438
|
const nudge = (reason) => {
|
|
@@ -7292,12 +7520,12 @@ function workSliceGuard(options2) {
|
|
|
7292
7520
|
}
|
|
7293
7521
|
return end("compaction-thrash", "three compactions");
|
|
7294
7522
|
}
|
|
7295
|
-
const
|
|
7296
|
-
if (
|
|
7523
|
+
const limit2 = sliceLimitReached(policy, state);
|
|
7524
|
+
if (limit2) {
|
|
7297
7525
|
state.endedBy = "budget";
|
|
7298
|
-
state.endedByLimit =
|
|
7526
|
+
state.endedByLimit = limit2;
|
|
7299
7527
|
state.refusedAt ??= state.steps;
|
|
7300
|
-
return handoff ? void 0 : { block: true, reason: handoffRequest(
|
|
7528
|
+
return handoff ? void 0 : { block: true, reason: handoffRequest(limit2, state, canCheckpoint) };
|
|
7301
7529
|
}
|
|
7302
7530
|
if (handoff) return void 0;
|
|
7303
7531
|
if (name === "todo_write") return void 0;
|
|
@@ -7318,11 +7546,11 @@ function workSliceGuard(options2) {
|
|
|
7318
7546
|
});
|
|
7319
7547
|
};
|
|
7320
7548
|
}
|
|
7321
|
-
function sliceOf(root, runId,
|
|
7549
|
+
function sliceOf(root, runId, limit2 = 100) {
|
|
7322
7550
|
let current2 = runId;
|
|
7323
7551
|
let count = 0;
|
|
7324
7552
|
const seen = /* @__PURE__ */ new Set();
|
|
7325
|
-
while (current2 && count <
|
|
7553
|
+
while (current2 && count < limit2 && !seen.has(current2)) {
|
|
7326
7554
|
seen.add(current2);
|
|
7327
7555
|
count += 1;
|
|
7328
7556
|
current2 = findRun(root, current2)?.resumedFromRunId ?? null;
|
|
@@ -7347,6 +7575,8 @@ function reported(parentRunId, results, spawned) {
|
|
|
7347
7575
|
return { text: JSON.stringify({ results: included, ...results.length > included.length ? { remaining: results.slice(included.length).map((result) => result.runId) } : {} }), details: { [SUBAGENT_RECEIPT]: receipt } };
|
|
7348
7576
|
}
|
|
7349
7577
|
function subagentTools(service, parentRunId) {
|
|
7578
|
+
const quota = service.quota(parentRunId);
|
|
7579
|
+
const budget = `This run allows at most ${quota.children} children: ${Object.entries(quota.profiles).map(([name, value]) => `${value} ${name}`).join(", ")}, ${quota.other} of any other profile and ${quota.unprofiled} unprofiled; a refused spawn means do the work yourself.`;
|
|
7350
7580
|
const execute = (fn) => async (input) => {
|
|
7351
7581
|
try {
|
|
7352
7582
|
return await fn(input);
|
|
@@ -7358,7 +7588,7 @@ function subagentTools(service, parentRunId) {
|
|
|
7358
7588
|
return [{
|
|
7359
7589
|
name: SPAWN_SUBAGENT,
|
|
7360
7590
|
label: "Start a subagent",
|
|
7361
|
-
description: "Start a fresh child run for independent work. Delegate substantial, bounded tasks that benefit from a separate context, not simple lookups, tiny edits or tightly coupled steps. Prefer a named specialist profile; omit agent only when no profile fits. Plan mode permits only eligible read-only research profiles. Give a short title and a self-contained brief: the child has no conversation history and no more capabilities than you. The optional tools field only narrows the profile and parent intersection; in plan mode, omit it unless you need a stricter subset. Returns its run ID immediately by default so you can continue other useful work. Results arrive automatically before you finish. Use wait_subagents when you need results before proceeding, or wait: true for an inline result. Avoid overlapping write assignments. Stopping you stops your children. To resume a child that stopped before finishing (interrupted or failed), pass continue with its run ID and no title, agent or tools: it reopens that child's own conversation with the same profile and tools, and brief becomes an optional extra instruction.",
|
|
7591
|
+
description: "Start a fresh child run for independent work. Delegate substantial, bounded tasks that benefit from a separate context, not simple lookups, tiny edits or tightly coupled steps. Prefer a named specialist profile; omit agent only when no profile fits. Plan mode permits only eligible read-only research profiles. Give a short title and a self-contained brief: the child has no conversation history and no more capabilities than you. The optional tools field only narrows the profile and parent intersection; in plan mode, omit it unless you need a stricter subset. Returns its run ID immediately by default so you can continue other useful work. Results arrive automatically before you finish. Use wait_subagents when you need results before proceeding, or wait: true for an inline result. Avoid overlapping write assignments. Stopping you stops your children. To resume a child that stopped before finishing (interrupted or failed), pass continue with its run ID and no title, agent or tools: it reopens that child's own conversation with the same profile and tools, and brief becomes an optional extra instruction. " + budget,
|
|
7362
7592
|
planModeSafe: (input) => service.planSpawnRefusal(parentRunId, input) === null,
|
|
7363
7593
|
parameters: (Type3) => Type3.Object({
|
|
7364
7594
|
title: Type3.Optional(Type3.String({ description: `Required for a new child: a short imperative title for the roster, at most ${MAX_SUBAGENT_TITLE_WORDS} words, such as "Map the auth flow"` })),
|
|
@@ -7395,13 +7625,13 @@ import { gfm } from "turndown-plugin-gfm";
|
|
|
7395
7625
|
var MAX_DEPTH = 512;
|
|
7396
7626
|
var INVISIBLE = 'script, style, noscript, template, iframe, object, embed, svg, canvas, head, link, meta, input[type="hidden"], [hidden], [aria-hidden="true"]';
|
|
7397
7627
|
var HIDING_STYLE = /(?:^|;)\s*(?:display\s*:\s*none|visibility\s*:\s*hidden|opacity\s*:\s*0(?:\.0+)?\s*(?:;|$)|font-size\s*:\s*0(?:px)?\s*(?:;|$))/i;
|
|
7398
|
-
function depth(node,
|
|
7628
|
+
function depth(node, limit2) {
|
|
7399
7629
|
let deepest = 0;
|
|
7400
7630
|
const stack = [[node, 0]];
|
|
7401
7631
|
while (stack.length) {
|
|
7402
7632
|
const [current2, level] = stack.pop();
|
|
7403
7633
|
if (level > deepest) deepest = level;
|
|
7404
|
-
if (deepest >
|
|
7634
|
+
if (deepest > limit2) return deepest;
|
|
7405
7635
|
for (let index = 0; index < current2.childNodes.length; index += 1) {
|
|
7406
7636
|
const child = current2.childNodes[index];
|
|
7407
7637
|
if (child.nodeType === 1) stack.push([child, level + 1]);
|
|
@@ -7701,16 +7931,16 @@ var Searcher = class {
|
|
|
7701
7931
|
return { provider: null, results: [], failures };
|
|
7702
7932
|
}
|
|
7703
7933
|
};
|
|
7704
|
-
function mergeResults(lists,
|
|
7934
|
+
function mergeResults(lists, limit2) {
|
|
7705
7935
|
const seen = /* @__PURE__ */ new Set();
|
|
7706
7936
|
const merged = [];
|
|
7707
|
-
for (let round3 = 0; merged.length <
|
|
7937
|
+
for (let round3 = 0; merged.length < limit2 && lists.some((list7) => round3 < list7.length); round3 += 1) {
|
|
7708
7938
|
for (const list7 of lists) {
|
|
7709
7939
|
const entry2 = list7[round3];
|
|
7710
7940
|
if (!entry2 || seen.has(entry2.url)) continue;
|
|
7711
7941
|
seen.add(entry2.url);
|
|
7712
7942
|
merged.push(entry2);
|
|
7713
|
-
if (merged.length >=
|
|
7943
|
+
if (merged.length >= limit2) break;
|
|
7714
7944
|
}
|
|
7715
7945
|
}
|
|
7716
7946
|
return merged;
|
|
@@ -7912,12 +8142,12 @@ function webPart(options2) {
|
|
|
7912
8142
|
|
|
7913
8143
|
// src/browser/index.ts
|
|
7914
8144
|
import { rmSync as rmSync10 } from "node:fs";
|
|
7915
|
-
import { join as
|
|
8145
|
+
import { join as join32 } from "node:path";
|
|
7916
8146
|
|
|
7917
8147
|
// src/browser/config.ts
|
|
7918
8148
|
init_fs();
|
|
7919
|
-
import { join as
|
|
7920
|
-
var configPath = (stateDir) =>
|
|
8149
|
+
import { join as join30 } from "node:path";
|
|
8150
|
+
var configPath = (stateDir) => join30(stateDir, "browser.json");
|
|
7921
8151
|
function readBrowserConfig(stateDir) {
|
|
7922
8152
|
const saved = readJsonOr(configPath(stateDir), {});
|
|
7923
8153
|
return {
|
|
@@ -8020,7 +8250,7 @@ var NetworkPolicy = class {
|
|
|
8020
8250
|
// src/browser/session.ts
|
|
8021
8251
|
import { mkdirSync as mkdirSync10, mkdtempSync as mkdtempSync2, rmSync as rmSync9 } from "node:fs";
|
|
8022
8252
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
8023
|
-
import { join as
|
|
8253
|
+
import { join as join31 } from "node:path";
|
|
8024
8254
|
var fileName = (name) => name.replace(/[^A-Za-z0-9._-]/g, "_").replace(/^\.+/, "_").slice(0, 100) || "_";
|
|
8025
8255
|
var VIEWPORT = { width: 1280, height: 800 };
|
|
8026
8256
|
var ACTION_TIMEOUT_MS = 15e3;
|
|
@@ -8089,7 +8319,7 @@ var BrowserSession = class {
|
|
|
8089
8319
|
launched = await this.options.launch({ profileDir: this.options.profileDir, downloads: this.options.downloadsDir, config: this.options.config() });
|
|
8090
8320
|
} catch (error) {
|
|
8091
8321
|
if (!this.options.profileDir || !/ProcessSingleton|already in use|lock/i.test(String(error))) throw error;
|
|
8092
|
-
this.temporaryProfile = mkdtempSync2(
|
|
8322
|
+
this.temporaryProfile = mkdtempSync2(join31(tmpdir2(), `harness-browser-${fileName(this.options.key)}-`));
|
|
8093
8323
|
launched = await this.options.launch({ profileDir: this.temporaryProfile, downloads: this.options.downloadsDir, config: this.options.config() });
|
|
8094
8324
|
this.profileNote = "The saved browser profile is in use by another session, so this one started without its sign-ins.";
|
|
8095
8325
|
}
|
|
@@ -8131,7 +8361,7 @@ var BrowserSession = class {
|
|
|
8131
8361
|
});
|
|
8132
8362
|
page2.on("download", (download) => {
|
|
8133
8363
|
const name = fileName(download.suggestedFilename() || "download");
|
|
8134
|
-
const path4 =
|
|
8364
|
+
const path4 = join31(this.options.downloadsDir, `${Date.now()}-${name}`);
|
|
8135
8365
|
void download.saveAs(path4).then(() => this.downloads.push({ tab: tab.id, path: path4, name })).catch(() => void 0);
|
|
8136
8366
|
});
|
|
8137
8367
|
return tab;
|
|
@@ -8642,8 +8872,8 @@ function createBrowserEngine(options2) {
|
|
|
8642
8872
|
if (diagnostic) diagnosticKeys.add(key);
|
|
8643
8873
|
session = new BrowserSession({
|
|
8644
8874
|
key,
|
|
8645
|
-
profileDir: diagnostic ? null :
|
|
8646
|
-
downloadsDir:
|
|
8875
|
+
profileDir: diagnostic ? null : join32(options2.stateDir, "browser", "profiles", fileName(owner)),
|
|
8876
|
+
downloadsDir: join32(options2.stateDir, "browser", "downloads", fileName(key)),
|
|
8647
8877
|
config: diagnostic ? () => ({ ...config(), cdpUrl: null, headed: false }) : config,
|
|
8648
8878
|
network,
|
|
8649
8879
|
launch: options2.launch ?? launchBrowser,
|
|
@@ -8658,7 +8888,7 @@ function createBrowserEngine(options2) {
|
|
|
8658
8888
|
const session = sessions.get(key);
|
|
8659
8889
|
sessions.delete(key);
|
|
8660
8890
|
await session?.close();
|
|
8661
|
-
if (diagnosticKeys.delete(key)) rmSync10(
|
|
8891
|
+
if (diagnosticKeys.delete(key)) rmSync10(join32(options2.stateDir, "browser", "downloads", fileName(key)), { recursive: true, force: true });
|
|
8662
8892
|
};
|
|
8663
8893
|
return {
|
|
8664
8894
|
diagnostics: () => [browserDiagnostic(config)],
|
|
@@ -8677,8 +8907,8 @@ function browserPluginPart(engine) {
|
|
|
8677
8907
|
// src/annotations/store.ts
|
|
8678
8908
|
init_errors();
|
|
8679
8909
|
init_fs();
|
|
8680
|
-
import { existsSync as
|
|
8681
|
-
import { join as
|
|
8910
|
+
import { existsSync as existsSync13, lstatSync as lstatSync6, mkdirSync as mkdirSync11, readdirSync as readdirSync16, rmSync as rmSync11 } from "node:fs";
|
|
8911
|
+
import { join as join33 } from "node:path";
|
|
8682
8912
|
var MAX_NOTES = 1e4;
|
|
8683
8913
|
var MAX_HISTORY = 100;
|
|
8684
8914
|
var codepoints = (value) => Array.from(value).length;
|
|
@@ -8794,16 +9024,16 @@ function visibleTo(note, caller) {
|
|
|
8794
9024
|
return note.grants.some((grant2) => grant2.principal.sessionId && grant2.principal.sessionId === caller.sessionId || grant2.principal.agentId && grant2.principal.agentId === caller.agentId);
|
|
8795
9025
|
}
|
|
8796
9026
|
function notesDir(root) {
|
|
8797
|
-
return
|
|
9027
|
+
return join33(root, "annotations");
|
|
8798
9028
|
}
|
|
8799
9029
|
function folder(root) {
|
|
8800
9030
|
const dir2 = notesDir(root);
|
|
8801
|
-
if (
|
|
9031
|
+
if (existsSync13(dir2) && (lstatSync6(dir2).isSymbolicLink() || !lstatSync6(dir2).isDirectory())) throw new HarnessError("invalid_data", "Note storage must be a plain folder.");
|
|
8802
9032
|
mkdirSync11(dir2, { recursive: true });
|
|
8803
9033
|
return dir2;
|
|
8804
9034
|
}
|
|
8805
9035
|
function file(root, id) {
|
|
8806
|
-
return
|
|
9036
|
+
return join33(folder(root), `${safeId(id)}.json`);
|
|
8807
9037
|
}
|
|
8808
9038
|
function validNote(note, id) {
|
|
8809
9039
|
if (!note || note.id !== id || note.author !== "user" || !Number.isSafeInteger(note.version) || note.version < 1 || !Array.isArray(note.grants) || !Array.isArray(note.history)) {
|
|
@@ -8826,13 +9056,13 @@ function upgradeDelivery(note) {
|
|
|
8826
9056
|
}
|
|
8827
9057
|
function read2(root, id) {
|
|
8828
9058
|
const path4 = file(root, id);
|
|
8829
|
-
if (!
|
|
9059
|
+
if (!existsSync13(path4)) throw notFound("Note");
|
|
8830
9060
|
if (lstatSync6(path4).isSymbolicLink()) throw new HarnessError("invalid_data", "Note records must not be links.");
|
|
8831
9061
|
return validNote(readJson(path4), id);
|
|
8832
9062
|
}
|
|
8833
9063
|
function all2(root) {
|
|
8834
9064
|
const notes = [];
|
|
8835
|
-
for (const name of
|
|
9065
|
+
for (const name of readdirSync16(folder(root))) {
|
|
8836
9066
|
if (!name.endsWith(".json")) continue;
|
|
8837
9067
|
try {
|
|
8838
9068
|
notes.push(read2(root, name.slice(0, -".json".length)));
|
|
@@ -8851,8 +9081,8 @@ function listAll(root, filter = {}) {
|
|
|
8851
9081
|
function list2(root, filter = {}) {
|
|
8852
9082
|
const matching = matchingNotes(root, filter);
|
|
8853
9083
|
const offset = Math.max(0, Math.floor(filter.offset ?? 0));
|
|
8854
|
-
const
|
|
8855
|
-
return { notes: matching.slice(offset, offset +
|
|
9084
|
+
const limit2 = Math.max(1, Math.min(200, Math.floor(filter.limit ?? 50)));
|
|
9085
|
+
return { notes: matching.slice(offset, offset + limit2), total: matching.length };
|
|
8856
9086
|
}
|
|
8857
9087
|
function save2(root, note, operation) {
|
|
8858
9088
|
note.version += 1;
|
|
@@ -8872,7 +9102,7 @@ function create(root, input) {
|
|
|
8872
9102
|
const target = validateTarget(input?.target);
|
|
8873
9103
|
const body2 = normalizeBody(input?.body);
|
|
8874
9104
|
const tags = normalizeTags(input?.tags);
|
|
8875
|
-
if (
|
|
9105
|
+
if (readdirSync16(folder(root)).filter((name) => name.endsWith(".json")).length >= MAX_NOTES) {
|
|
8876
9106
|
throw new HarnessError("annotation_limit", `At most ${MAX_NOTES} notes may be kept.`);
|
|
8877
9107
|
}
|
|
8878
9108
|
const at = now();
|
|
@@ -8930,7 +9160,7 @@ function importNotes(root, notes) {
|
|
|
8930
9160
|
try {
|
|
8931
9161
|
if (!id) throw invalid("A note needs an id.");
|
|
8932
9162
|
safeId(id);
|
|
8933
|
-
if (
|
|
9163
|
+
if (existsSync13(file(root, id))) {
|
|
8934
9164
|
skipped.push({ id, reason: "exists" });
|
|
8935
9165
|
continue;
|
|
8936
9166
|
}
|
|
@@ -10180,16 +10410,16 @@ function hubServerMethods(harness) {
|
|
|
10180
10410
|
|
|
10181
10411
|
// src/refine/runner.ts
|
|
10182
10412
|
init_fs();
|
|
10183
|
-
import { join as
|
|
10413
|
+
import { join as join38 } from "node:path";
|
|
10184
10414
|
|
|
10185
10415
|
// src/refine/library.ts
|
|
10186
10416
|
init_fs();
|
|
10187
|
-
import { existsSync as
|
|
10188
|
-
import { join as
|
|
10417
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync13, readdirSync as readdirSync18, readFileSync as readFileSync19, rmSync as rmSync13, writeFileSync as writeFileSync4 } from "node:fs";
|
|
10418
|
+
import { join as join35 } from "node:path";
|
|
10189
10419
|
|
|
10190
10420
|
// src/refine/evidence.ts
|
|
10191
|
-
import { copyFileSync as copyFileSync4, cpSync, existsSync as
|
|
10192
|
-
import { dirname as
|
|
10421
|
+
import { copyFileSync as copyFileSync4, cpSync, existsSync as existsSync14, mkdirSync as mkdirSync12, readdirSync as readdirSync17, readFileSync as readFileSync18, rmSync as rmSync12, statSync as statSync10, writeFileSync as writeFileSync3 } from "node:fs";
|
|
10422
|
+
import { dirname as dirname12, extname as extname2, join as join34, relative as relative5, sep as sep7 } from "node:path";
|
|
10193
10423
|
var GRADER_VERDICT_MARKERS = [
|
|
10194
10424
|
"deterministic_eval_summary",
|
|
10195
10425
|
"deterministic_eval_result",
|
|
@@ -10207,15 +10437,15 @@ function files(dir2) {
|
|
|
10207
10437
|
const out = [];
|
|
10208
10438
|
let names2;
|
|
10209
10439
|
try {
|
|
10210
|
-
names2 =
|
|
10440
|
+
names2 = readdirSync17(dir2);
|
|
10211
10441
|
} catch {
|
|
10212
10442
|
return out;
|
|
10213
10443
|
}
|
|
10214
10444
|
for (const name of names2.sort()) {
|
|
10215
|
-
const path4 =
|
|
10445
|
+
const path4 = join34(dir2, name);
|
|
10216
10446
|
let isDir2 = false;
|
|
10217
10447
|
try {
|
|
10218
|
-
isDir2 =
|
|
10448
|
+
isDir2 = statSync10(path4).isDirectory();
|
|
10219
10449
|
} catch {
|
|
10220
10450
|
continue;
|
|
10221
10451
|
}
|
|
@@ -10238,13 +10468,13 @@ function globToRegExp(glob) {
|
|
|
10238
10468
|
return new RegExp(`^(?:[^]*/)?${out}$`);
|
|
10239
10469
|
}
|
|
10240
10470
|
function assertNoLeakPaths(root, globs = []) {
|
|
10241
|
-
if (!globs.length || !
|
|
10471
|
+
if (!globs.length || !existsSync14(root)) return;
|
|
10242
10472
|
const rx = globs.map(globToRegExp);
|
|
10243
10473
|
const hits = files(root).map((path4) => rel(root, path4)).filter((path4) => rx.some((r) => r.test(path4)));
|
|
10244
10474
|
if (hits.length) throw new Error(`answer-key path(s) would enter model context: ${hits.sort().slice(0, 8).join(", ")}`);
|
|
10245
10475
|
}
|
|
10246
10476
|
function assertNoGraderVerdicts(root, markers = GRADER_VERDICT_MARKERS) {
|
|
10247
|
-
if (!
|
|
10477
|
+
if (!existsSync14(root)) return;
|
|
10248
10478
|
for (const path4 of files(root)) {
|
|
10249
10479
|
const name = rel(root, path4);
|
|
10250
10480
|
for (const marker of markers) {
|
|
@@ -10253,7 +10483,7 @@ function assertNoGraderVerdicts(root, markers = GRADER_VERDICT_MARKERS) {
|
|
|
10253
10483
|
if (!SCANNED.has(extname2(path4).toLowerCase())) continue;
|
|
10254
10484
|
let body2;
|
|
10255
10485
|
try {
|
|
10256
|
-
body2 =
|
|
10486
|
+
body2 = readFileSync18(path4, "utf8");
|
|
10257
10487
|
} catch {
|
|
10258
10488
|
continue;
|
|
10259
10489
|
}
|
|
@@ -10275,8 +10505,8 @@ function copyFolder(src, dst) {
|
|
|
10275
10505
|
let n = 0;
|
|
10276
10506
|
for (const path4 of files(src)) {
|
|
10277
10507
|
if (path4.includes(`${sep7}__pycache__${sep7}`) || path4.endsWith(".pyc")) continue;
|
|
10278
|
-
const target =
|
|
10279
|
-
mkdirSync12(
|
|
10508
|
+
const target = join34(dst, relative5(src, path4));
|
|
10509
|
+
mkdirSync12(dirname12(target), { recursive: true });
|
|
10280
10510
|
copyFileSync4(path4, target);
|
|
10281
10511
|
n++;
|
|
10282
10512
|
}
|
|
@@ -10284,18 +10514,18 @@ function copyFolder(src, dst) {
|
|
|
10284
10514
|
}
|
|
10285
10515
|
function copySource(task, root) {
|
|
10286
10516
|
const src = task.sourceDir;
|
|
10287
|
-
if (!src || !
|
|
10517
|
+
if (!src || !existsSync14(src)) return 0;
|
|
10288
10518
|
const leak = (task.leakGlobs ?? []).map(globToRegExp);
|
|
10289
10519
|
let n = 0;
|
|
10290
10520
|
for (const path4 of files(src)) {
|
|
10291
10521
|
const name = rel(src, path4);
|
|
10292
10522
|
if (name.split("/").includes("__pycache__") || leak.some((r) => r.test(name))) continue;
|
|
10293
|
-
const target =
|
|
10294
|
-
mkdirSync12(
|
|
10523
|
+
const target = join34(root, "source", name);
|
|
10524
|
+
mkdirSync12(dirname12(target), { recursive: true });
|
|
10295
10525
|
copyFileSync4(path4, target);
|
|
10296
10526
|
n++;
|
|
10297
10527
|
}
|
|
10298
|
-
if (n) assertNoLeakPaths(
|
|
10528
|
+
if (n) assertNoLeakPaths(join34(root, "source"), task.leakGlobs);
|
|
10299
10529
|
return n;
|
|
10300
10530
|
}
|
|
10301
10531
|
function unifiedDiff(before, after, fromLabel, toLabel) {
|
|
@@ -10345,15 +10575,15 @@ function layout(evidence) {
|
|
|
10345
10575
|
}
|
|
10346
10576
|
function writeRollout(dest, rollout, executor, obsTrunc) {
|
|
10347
10577
|
let failure2 = "";
|
|
10348
|
-
mkdirSync12(
|
|
10578
|
+
mkdirSync12(join34(dest, "rollouts"), { recursive: true });
|
|
10349
10579
|
try {
|
|
10350
|
-
writeFileSync3(
|
|
10580
|
+
writeFileSync3(join34(dest, "rollouts", `${rollout.label}.md`), executor.trajectory(rollout, { obsTrunc }));
|
|
10351
10581
|
} catch (error) {
|
|
10352
10582
|
const message4 = error instanceof Error ? error.message : String(error);
|
|
10353
|
-
writeFileSync3(
|
|
10583
|
+
writeFileSync3(join34(dest, "rollouts", `${rollout.label}.md`), `(trajectory unavailable: ${message4})`);
|
|
10354
10584
|
failure2 = `${rollout.label}: ${message4}`;
|
|
10355
10585
|
}
|
|
10356
|
-
const dir2 =
|
|
10586
|
+
const dir2 = join34(dest, "deliverables", rollout.label);
|
|
10357
10587
|
mkdirSync12(dir2, { recursive: true });
|
|
10358
10588
|
let produced = {};
|
|
10359
10589
|
try {
|
|
@@ -10363,11 +10593,11 @@ function writeRollout(dest, rollout, executor, obsTrunc) {
|
|
|
10363
10593
|
}
|
|
10364
10594
|
const names2 = Object.keys(produced).sort();
|
|
10365
10595
|
for (const name of names2) {
|
|
10366
|
-
const target =
|
|
10367
|
-
mkdirSync12(
|
|
10596
|
+
const target = join34(dir2, name);
|
|
10597
|
+
mkdirSync12(dirname12(target), { recursive: true });
|
|
10368
10598
|
writeFileSync3(target, produced[name]);
|
|
10369
10599
|
}
|
|
10370
|
-
writeFileSync3(
|
|
10600
|
+
writeFileSync3(join34(dir2, "INDEX.md"), names2.length ? `# ${rollout.label} produced ${names2.length} file(s)
|
|
10371
10601
|
|
|
10372
10602
|
${names2.map((name) => `- \`${name}\``).join("\n")}
|
|
10373
10603
|
` : `# ${rollout.label} produced nothing
|
|
@@ -10388,11 +10618,11 @@ function build(dest, input) {
|
|
|
10388
10618
|
rmSync12(dest, { recursive: true, force: true });
|
|
10389
10619
|
mkdirSync12(dest, { recursive: true });
|
|
10390
10620
|
const obsTrunc = Math.max(input.obsTrunc ?? 5e4, MIN_OBS_TRUNC);
|
|
10391
|
-
writeFileSync3(
|
|
10621
|
+
writeFileSync3(join34(dest, "task.md"), task.prompt);
|
|
10392
10622
|
const sourceFiles = copySource(task, dest);
|
|
10393
10623
|
for (const [label, notes] of Object.entries(input.decisions ?? {})) {
|
|
10394
|
-
mkdirSync12(
|
|
10395
|
-
writeFileSync3(
|
|
10624
|
+
mkdirSync12(join34(dest, "decisions"), { recursive: true });
|
|
10625
|
+
writeFileSync3(join34(dest, "decisions", `${label}.md`), notes || "No decision notes returned.");
|
|
10396
10626
|
}
|
|
10397
10627
|
const rollouts = [];
|
|
10398
10628
|
const deliverables = [];
|
|
@@ -10404,35 +10634,35 @@ function build(dest, input) {
|
|
|
10404
10634
|
deliverables.push(rollout.label);
|
|
10405
10635
|
}
|
|
10406
10636
|
let harnessFiles = 0;
|
|
10407
|
-
if (input.variantDir &&
|
|
10637
|
+
if (input.variantDir && existsSync14(input.variantDir)) {
|
|
10408
10638
|
assertNoLeakPaths(input.variantDir, task.leakGlobs);
|
|
10409
|
-
harnessFiles = copyFolder(input.variantDir,
|
|
10639
|
+
harnessFiles = copyFolder(input.variantDir, join34(dest, "harness"));
|
|
10410
10640
|
}
|
|
10411
10641
|
const pool = [];
|
|
10412
10642
|
for (const entry2 of input.pool ?? []) {
|
|
10413
|
-
const dir2 =
|
|
10643
|
+
const dir2 = join34(dest, "pool", entry2.label);
|
|
10414
10644
|
mkdirSync12(dir2, { recursive: true });
|
|
10415
|
-
if (entry2.variantDir &&
|
|
10645
|
+
if (entry2.variantDir && existsSync14(entry2.variantDir)) {
|
|
10416
10646
|
assertNoLeakPaths(entry2.variantDir, task.leakGlobs);
|
|
10417
|
-
copyFolder(entry2.variantDir,
|
|
10418
|
-
const reference = readVariant(PI_SURFACE,
|
|
10647
|
+
copyFolder(entry2.variantDir, join34(dir2, "harness"));
|
|
10648
|
+
const reference = readVariant(PI_SURFACE, join34(dest, "harness"));
|
|
10419
10649
|
const candidate = readVariant(PI_SURFACE, entry2.variantDir);
|
|
10420
|
-
writeFileSync3(
|
|
10650
|
+
writeFileSync3(join34(dir2, "harness.diff"), unifiedDiff(reference, candidate, "current", entry2.label));
|
|
10421
10651
|
}
|
|
10422
10652
|
if (entry2.rollout) {
|
|
10423
10653
|
try {
|
|
10424
|
-
writeFileSync3(
|
|
10425
|
-
writeFileSync3(
|
|
10654
|
+
writeFileSync3(join34(dir2, "rollout.md"), executor.trajectory(entry2.rollout, { obsTrunc }));
|
|
10655
|
+
writeFileSync3(join34(dir2, "produced.md"), renderDeliverable(executor, entry2.rollout) || "(nothing produced)");
|
|
10426
10656
|
} catch (error) {
|
|
10427
|
-
writeFileSync3(
|
|
10657
|
+
writeFileSync3(join34(dir2, "rollout.md"), `(unavailable: ${error instanceof Error ? error.message : String(error)})`);
|
|
10428
10658
|
}
|
|
10429
10659
|
}
|
|
10430
10660
|
pool.push(entry2.label);
|
|
10431
10661
|
}
|
|
10432
10662
|
let library = false;
|
|
10433
|
-
if (input.libraryDir &&
|
|
10663
|
+
if (input.libraryDir && existsSync14(input.libraryDir) && readdirSync17(input.libraryDir).length) {
|
|
10434
10664
|
assertNoLeakPaths(input.libraryDir, task.leakGlobs);
|
|
10435
|
-
cpSync(input.libraryDir,
|
|
10665
|
+
cpSync(input.libraryDir, join34(dest, "library"), { recursive: true });
|
|
10436
10666
|
library = true;
|
|
10437
10667
|
}
|
|
10438
10668
|
assertNoLeakPaths(dest, task.leakGlobs);
|
|
@@ -10466,7 +10696,7 @@ function slug(text10) {
|
|
|
10466
10696
|
return text10.replace(/\s*[/\\]\s*/g, "__").replace(/[^A-Za-z0-9_.\-]/g, "_").replace(/^\.+/, "_").slice(0, 120).trim() || "unknown";
|
|
10467
10697
|
}
|
|
10468
10698
|
function libraryRoot(root) {
|
|
10469
|
-
return
|
|
10699
|
+
return join35(root, "library");
|
|
10470
10700
|
}
|
|
10471
10701
|
var Library = class {
|
|
10472
10702
|
constructor(root, scope, area = scope, surface = PI_SURFACE) {
|
|
@@ -10481,39 +10711,39 @@ var Library = class {
|
|
|
10481
10711
|
area;
|
|
10482
10712
|
surface;
|
|
10483
10713
|
get dir() {
|
|
10484
|
-
return
|
|
10714
|
+
return join35(libraryRoot(this.root), this.scope, slug(this.area));
|
|
10485
10715
|
}
|
|
10486
10716
|
get index() {
|
|
10487
|
-
return
|
|
10717
|
+
return join35(this.dir, "INDEX.md");
|
|
10488
10718
|
}
|
|
10489
10719
|
entryDir(task) {
|
|
10490
|
-
return
|
|
10720
|
+
return join35(this.dir, "variants", slug(task));
|
|
10491
10721
|
}
|
|
10492
10722
|
/** The folder handed to an improver, or null when nothing has been learned here yet. */
|
|
10493
10723
|
contextDir() {
|
|
10494
|
-
return
|
|
10724
|
+
return existsSync15(this.index) && this.entries().length ? this.dir : null;
|
|
10495
10725
|
}
|
|
10496
10726
|
entries() {
|
|
10497
|
-
const dir2 =
|
|
10727
|
+
const dir2 = join35(this.dir, "variants");
|
|
10498
10728
|
try {
|
|
10499
|
-
return
|
|
10729
|
+
return readdirSync18(dir2, { withFileTypes: true }).filter((entry2) => entry2.isDirectory() && existsSync15(join35(dir2, entry2.name, "EXPERIENCE.md"))).map((entry2) => entry2.name).sort();
|
|
10500
10730
|
} catch {
|
|
10501
10731
|
return [];
|
|
10502
10732
|
}
|
|
10503
10733
|
}
|
|
10504
10734
|
variantOf(task) {
|
|
10505
|
-
return readVariant(this.surface,
|
|
10735
|
+
return readVariant(this.surface, join35(this.entryDir(task), "variant"));
|
|
10506
10736
|
}
|
|
10507
10737
|
experienceText(task) {
|
|
10508
10738
|
try {
|
|
10509
|
-
return
|
|
10739
|
+
return readFileSync19(join35(this.entryDir(task), "EXPERIENCE.md"), "utf8");
|
|
10510
10740
|
} catch {
|
|
10511
10741
|
return null;
|
|
10512
10742
|
}
|
|
10513
10743
|
}
|
|
10514
10744
|
list() {
|
|
10515
10745
|
return this.entries().map((name) => {
|
|
10516
|
-
const text10 =
|
|
10746
|
+
const text10 = readFileSync19(join35(this.dir, "variants", name, "EXPERIENCE.md"), "utf8");
|
|
10517
10747
|
return {
|
|
10518
10748
|
task: name,
|
|
10519
10749
|
label: /^- adopted: `([^`]+)`/m.exec(text10)?.[1] ?? "",
|
|
@@ -10528,7 +10758,7 @@ var Library = class {
|
|
|
10528
10758
|
let removed = false;
|
|
10529
10759
|
for (const task of tasks) {
|
|
10530
10760
|
const dir2 = this.entryDir(task);
|
|
10531
|
-
if (
|
|
10761
|
+
if (existsSync15(dir2)) {
|
|
10532
10762
|
rmSync13(dir2, { recursive: true, force: true });
|
|
10533
10763
|
removed = true;
|
|
10534
10764
|
}
|
|
@@ -10545,8 +10775,8 @@ var Library = class {
|
|
|
10545
10775
|
assertVariantHasNoGraderVerdicts(variant);
|
|
10546
10776
|
assertVariantHasNoGraderVerdicts({ "EXPERIENCE.md": JSON.stringify(experience2) + (input.why ?? "") });
|
|
10547
10777
|
const dir2 = this.entryDir(task);
|
|
10548
|
-
rmSync13(
|
|
10549
|
-
writeVariant(this.surface, variant,
|
|
10778
|
+
rmSync13(join35(dir2, "variant"), { recursive: true, force: true });
|
|
10779
|
+
writeVariant(this.surface, variant, join35(dir2, "variant"), { stubs: false });
|
|
10550
10780
|
const lines2 = [`# ${task}`, "", `- adopted: \`${input.label ?? ""}\`${input.runId ? ` (run \`${input.runId}\`)` : ""}`, `- components: ${inventory(this.surface, variant)}`, ""];
|
|
10551
10781
|
if (input.why?.trim()) lines2.push("## Why this was chosen", input.why.trim(), "");
|
|
10552
10782
|
if (experience2.edits?.trim()) lines2.push("## What each edit did", experience2.edits.trim(), "");
|
|
@@ -10554,7 +10784,7 @@ var Library = class {
|
|
|
10554
10784
|
for (const key of ["cue", "lesson", "evidence", "confidence"]) if (experience2[key]) lines2.push(`- **${key}**: ${String(experience2[key]).trim()}`);
|
|
10555
10785
|
lines2.push("");
|
|
10556
10786
|
mkdirSync13(dir2, { recursive: true });
|
|
10557
|
-
writeFileSync4(
|
|
10787
|
+
writeFileSync4(join35(dir2, "EXPERIENCE.md"), lines2.join("\n"));
|
|
10558
10788
|
this.rebuildIndex();
|
|
10559
10789
|
return dir2;
|
|
10560
10790
|
}
|
|
@@ -10563,7 +10793,7 @@ var Library = class {
|
|
|
10563
10793
|
const names2 = this.entries();
|
|
10564
10794
|
if (!names2.length) rows.push("_(empty \u2014 this is the first task in this area)_");
|
|
10565
10795
|
for (const name of names2) {
|
|
10566
|
-
const cue = field(
|
|
10796
|
+
const cue = field(readFileSync19(join35(this.dir, "variants", name, "EXPERIENCE.md"), "utf8"), "cue");
|
|
10567
10797
|
rows.push(`## \`variants/${name}/\``, `- variant: \`variants/${name}/variant/\` \u2014 ${inventory(this.surface, this.variantOf(name))}`, `- why: \`variants/${name}/EXPERIENCE.md\``);
|
|
10568
10798
|
if (cue) rows.push(`- cue: ${cue}`);
|
|
10569
10799
|
rows.push("");
|
|
@@ -10590,22 +10820,22 @@ function field(text10, name) {
|
|
|
10590
10820
|
}
|
|
10591
10821
|
function libraryScopes(root) {
|
|
10592
10822
|
try {
|
|
10593
|
-
return
|
|
10823
|
+
return readdirSync18(libraryRoot(root), { withFileTypes: true }).filter((entry2) => entry2.isDirectory()).map((entry2) => entry2.name).sort();
|
|
10594
10824
|
} catch {
|
|
10595
10825
|
return [];
|
|
10596
10826
|
}
|
|
10597
10827
|
}
|
|
10598
10828
|
function libraryAreas(root, scope) {
|
|
10599
10829
|
try {
|
|
10600
|
-
return
|
|
10830
|
+
return readdirSync18(join35(libraryRoot(root), safeId(scope)), { withFileTypes: true }).filter((entry2) => entry2.isDirectory()).map((entry2) => entry2.name).sort();
|
|
10601
10831
|
} catch {
|
|
10602
10832
|
return [];
|
|
10603
10833
|
}
|
|
10604
10834
|
}
|
|
10605
10835
|
|
|
10606
10836
|
// src/refine/recursion.ts
|
|
10607
|
-
import { existsSync as
|
|
10608
|
-
import { join as
|
|
10837
|
+
import { existsSync as existsSync16 } from "node:fs";
|
|
10838
|
+
import { join as join36 } from "node:path";
|
|
10609
10839
|
|
|
10610
10840
|
// src/refine/ledger.ts
|
|
10611
10841
|
var expectedRollouts = (k) => 4 * k;
|
|
@@ -11146,7 +11376,7 @@ async function runStage(ctx, input) {
|
|
|
11146
11376
|
let folder2;
|
|
11147
11377
|
let mission2;
|
|
11148
11378
|
try {
|
|
11149
|
-
folder2 = build(
|
|
11379
|
+
folder2 = build(join36(ctx.workDir, "context", label), {
|
|
11150
11380
|
task: ctx.task,
|
|
11151
11381
|
executor: ctx.executor,
|
|
11152
11382
|
rollouts: input.rollouts,
|
|
@@ -11193,7 +11423,7 @@ Fix it in \`context/harness/\` and reply again.` : ""),
|
|
|
11193
11423
|
usd += reply.costUsd;
|
|
11194
11424
|
attempts += reply.cached ? 0 : Math.max(1, reply.attempts);
|
|
11195
11425
|
allCached = allCached && reply.cached;
|
|
11196
|
-
if (!reply.workspace || !
|
|
11426
|
+
if (!reply.workspace || !existsSync16(reply.workspace)) {
|
|
11197
11427
|
err = "the harness directory did not come back from the session; edit the files in `context/harness/` in place";
|
|
11198
11428
|
continue;
|
|
11199
11429
|
}
|
|
@@ -11210,7 +11440,7 @@ Fix it in \`context/harness/\` and reply again.` : ""),
|
|
|
11210
11440
|
const accepted = acceptVariant(ctx.task, ctx.executor, next, fallback);
|
|
11211
11441
|
if (accepted.error) {
|
|
11212
11442
|
err = accepted.error;
|
|
11213
|
-
writeVariant(PI_SURFACE, next,
|
|
11443
|
+
writeVariant(PI_SURFACE, next, join36(folder2.root, "harness"));
|
|
11214
11444
|
continue;
|
|
11215
11445
|
}
|
|
11216
11446
|
const notes = /<notes>([\s\S]*?)<\/notes>/.exec(reply.text)?.[1]?.trim() ?? reply.text.trim();
|
|
@@ -11222,7 +11452,7 @@ function recordSessions(ledger, stages) {
|
|
|
11222
11452
|
for (const stage2 of stages) ledger.session(stage2.label, stage2.usd, { cached: stage2.cached, attempts: stage2.attempts });
|
|
11223
11453
|
}
|
|
11224
11454
|
async function roll(ctx, label, variant) {
|
|
11225
|
-
const variantDir = writeVariant(PI_SURFACE, variant,
|
|
11455
|
+
const variantDir = writeVariant(PI_SURFACE, variant, join36(ctx.workDir, "variants", label));
|
|
11226
11456
|
const runId = ctx.runIdOf(label);
|
|
11227
11457
|
ctx.onEvent?.({ type: "rollout.started", label });
|
|
11228
11458
|
let rollout;
|
|
@@ -11230,7 +11460,7 @@ async function roll(ctx, label, variant) {
|
|
|
11230
11460
|
checkAborted(ctx.signal);
|
|
11231
11461
|
rollout = await ctx.executor.execute(ctx.task, variantDir, label, runId);
|
|
11232
11462
|
} catch (error) {
|
|
11233
|
-
rollout = { label, runId, dir:
|
|
11463
|
+
rollout = { label, runId, dir: join36(ctx.workDir, "missing", label), ok: false, delivered: false, costUsd: 0, wallMs: 0, error: error instanceof Error ? error.message : String(error) };
|
|
11234
11464
|
}
|
|
11235
11465
|
ctx.onEvent?.({ type: "rollout.finished", label, ok: rollout.ok, delivered: rollout.delivered, error: rollout.error });
|
|
11236
11466
|
return rollout;
|
|
@@ -11249,7 +11479,7 @@ function newResult(mode2, ctx, k, base) {
|
|
|
11249
11479
|
for (const rollout of base) ledger.rollout(rollout.label, rollout.costUsd);
|
|
11250
11480
|
return { mode: mode2, taskId: ctx.task.id, k, stages: [], variants: {}, rollouts: Object.fromEntries(base.map((rollout) => [rollout.label, rollout])), finals: [], ledger, similarity: null, errors: [] };
|
|
11251
11481
|
}
|
|
11252
|
-
var variantPath = (ctx, label) =>
|
|
11482
|
+
var variantPath = (ctx, label) => join36(ctx.workDir, "variants", label);
|
|
11253
11483
|
async function runParallel(ctx, k, base) {
|
|
11254
11484
|
const result = newResult("agg", ctx, k, base);
|
|
11255
11485
|
const prompts = ctx.task.prompts ?? defaultPrompts();
|
|
@@ -11340,7 +11570,7 @@ function runMode(mode2, ctx, k, base) {
|
|
|
11340
11570
|
init_fs();
|
|
11341
11571
|
import { createHash as createHash6 } from "node:crypto";
|
|
11342
11572
|
import { cpSync as cpSync2, mkdirSync as mkdirSync14, rmSync as rmSync14, writeFileSync as writeFileSync5 } from "node:fs";
|
|
11343
|
-
import { join as
|
|
11573
|
+
import { join as join37 } from "node:path";
|
|
11344
11574
|
function seeded(seed2) {
|
|
11345
11575
|
let a = seed2 >>> 0;
|
|
11346
11576
|
return () => {
|
|
@@ -11404,7 +11634,7 @@ function renderPool(candidates, executor, sel) {
|
|
|
11404
11634
|
}
|
|
11405
11635
|
function persist(sel, root) {
|
|
11406
11636
|
try {
|
|
11407
|
-
writeJson(
|
|
11637
|
+
writeJson(join37(root, "selection.json"), sel);
|
|
11408
11638
|
} catch (error) {
|
|
11409
11639
|
sel.ok = false;
|
|
11410
11640
|
sel.error = `${sel.error} | could not persist selection: ${error instanceof Error ? error.message : String(error)}`.slice(0, 400);
|
|
@@ -11426,14 +11656,14 @@ async function runSelection(input) {
|
|
|
11426
11656
|
return sel;
|
|
11427
11657
|
}
|
|
11428
11658
|
sel.idMap = assignIds(Object.keys(pool), task.id, k, mode2);
|
|
11429
|
-
const root =
|
|
11659
|
+
const root = join37(input.workDir, "selection", `${mode2}${k}`);
|
|
11430
11660
|
rmSync14(root, { recursive: true, force: true });
|
|
11431
|
-
mkdirSync14(
|
|
11432
|
-
writeFileSync5(
|
|
11661
|
+
mkdirSync14(join37(root, "candidates"), { recursive: true });
|
|
11662
|
+
writeFileSync5(join37(root, "task.md"), task.prompt);
|
|
11433
11663
|
copySource(task, root);
|
|
11434
11664
|
for (const [anon, label] of Object.entries(sel.idMap)) {
|
|
11435
11665
|
const text10 = artifacts[label];
|
|
11436
|
-
writeFileSync5(
|
|
11666
|
+
writeFileSync5(join37(root, "candidates", `${anon}.md`), `<!-- candidate ${anon}: ${text10.length.toLocaleString("en-US")} chars, ${text10.split("\n").length.toLocaleString("en-US")} lines. COMPLETE -- nothing trimmed. Navigate with grep/offsets; evaluating a candidate means opening the part that determines whether it works. -->
|
|
11437
11667
|
${text10}`);
|
|
11438
11668
|
}
|
|
11439
11669
|
const ids2 = Object.keys(sel.idMap).sort().join(", ");
|
|
@@ -11485,7 +11715,7 @@ function trivialSelection(input) {
|
|
|
11485
11715
|
choose(sel, label, pool);
|
|
11486
11716
|
sel.ok = true;
|
|
11487
11717
|
sel.why = "trivial pool: single final at k=1; delivered without a selector session";
|
|
11488
|
-
const root =
|
|
11718
|
+
const root = join37(input.workDir, "selection", `${mode2}${k}`);
|
|
11489
11719
|
rmSync14(root, { recursive: true, force: true });
|
|
11490
11720
|
mkdirSync14(root, { recursive: true });
|
|
11491
11721
|
persist(sel, root);
|
|
@@ -11495,21 +11725,21 @@ async function reflectAdoption(input) {
|
|
|
11495
11725
|
const { task, selection: sel } = input;
|
|
11496
11726
|
const chosen = input.rollouts[sel.chosenLabel];
|
|
11497
11727
|
if (!sel.ok || !chosen) return {};
|
|
11498
|
-
const root =
|
|
11499
|
-
const variants =
|
|
11728
|
+
const root = join37(input.workDir, "reflection", `${sel.mode}${sel.k}`);
|
|
11729
|
+
const variants = join37(input.workDir, "variants");
|
|
11500
11730
|
let layout2 = "";
|
|
11501
11731
|
try {
|
|
11502
11732
|
const built = build(root, {
|
|
11503
11733
|
task,
|
|
11504
11734
|
executor: input.executor,
|
|
11505
11735
|
rollouts: Object.values(input.rollouts),
|
|
11506
|
-
variantDir:
|
|
11507
|
-
pool: Object.entries(input.rollouts).filter(([label]) => !label.startsWith("base")).map(([label, rollout]) => ({ label, variantDir:
|
|
11736
|
+
variantDir: join37(variants, sel.chosenLabel),
|
|
11737
|
+
pool: Object.entries(input.rollouts).filter(([label]) => !label.startsWith("base")).map(([label, rollout]) => ({ label, variantDir: join37(variants, label), rollout })),
|
|
11508
11738
|
decisions: input.decisions
|
|
11509
11739
|
});
|
|
11510
11740
|
layout2 = layout(built);
|
|
11511
|
-
writeVariant(PI_SURFACE, input.baseVariant,
|
|
11512
|
-
writeFileSync5(
|
|
11741
|
+
writeVariant(PI_SURFACE, input.baseVariant, join37(root, "base_harness"), { stubs: false });
|
|
11742
|
+
writeFileSync5(join37(root, "adoption.json"), `${JSON.stringify({ chosen_label: sel.chosenLabel, candidate_ids: sel.idMap, reason: sel.why }, null, 2)}
|
|
11513
11743
|
`);
|
|
11514
11744
|
assertNoLeakPaths(root, task.leakGlobs);
|
|
11515
11745
|
assertNoGraderVerdicts(root);
|
|
@@ -11541,7 +11771,7 @@ ${layout2}`
|
|
|
11541
11771
|
return {};
|
|
11542
11772
|
}
|
|
11543
11773
|
const out = parseExperience(text10);
|
|
11544
|
-
if (out.edits) writeFileSync5(
|
|
11774
|
+
if (out.edits) writeFileSync5(join37(root, "edits.md"), `${out.edits}
|
|
11545
11775
|
`);
|
|
11546
11776
|
try {
|
|
11547
11777
|
assertVariantHasNoGraderVerdicts({ "EXPERIENCE.md": JSON.stringify(out) });
|
|
@@ -11549,7 +11779,7 @@ ${layout2}`
|
|
|
11549
11779
|
return {};
|
|
11550
11780
|
}
|
|
11551
11781
|
sel.experience = out;
|
|
11552
|
-
persist(sel,
|
|
11782
|
+
persist(sel, join37(input.workDir, "selection", `${sel.mode}${sel.k}`));
|
|
11553
11783
|
return out;
|
|
11554
11784
|
}
|
|
11555
11785
|
function parseExperience(text10) {
|
|
@@ -11571,10 +11801,10 @@ function parseExperience(text10) {
|
|
|
11571
11801
|
|
|
11572
11802
|
// src/refine/runner.ts
|
|
11573
11803
|
function refineDir(root, id) {
|
|
11574
|
-
return
|
|
11804
|
+
return join38(root, "refine", safeId(id));
|
|
11575
11805
|
}
|
|
11576
11806
|
function readSummary(root, id) {
|
|
11577
|
-
return readJson(
|
|
11807
|
+
return readJson(join38(refineDir(root, id), "summary.json"));
|
|
11578
11808
|
}
|
|
11579
11809
|
var modeToken = (mode2) => mode2 === "parallel" ? "agg" : "seq";
|
|
11580
11810
|
async function runRefinement(input) {
|
|
@@ -11612,7 +11842,7 @@ async function runRefinement(input) {
|
|
|
11612
11842
|
...input.settings ? { settings: input.settings } : {}
|
|
11613
11843
|
};
|
|
11614
11844
|
const save3 = () => {
|
|
11615
|
-
writeJson(
|
|
11845
|
+
writeJson(join38(workDir, "summary.json"), summary4);
|
|
11616
11846
|
emit({ type: "summary", summary: structuredClone(summary4) });
|
|
11617
11847
|
};
|
|
11618
11848
|
const finish = (status) => {
|
|
@@ -11622,11 +11852,11 @@ async function runRefinement(input) {
|
|
|
11622
11852
|
emit({ type: "phase", phase: "done" });
|
|
11623
11853
|
return summary4;
|
|
11624
11854
|
};
|
|
11625
|
-
writeJson(
|
|
11855
|
+
writeJson(join38(workDir, "task.json"), { task, k, mode: mode2 });
|
|
11626
11856
|
save3();
|
|
11627
11857
|
const libraryDir = library.contextDir();
|
|
11628
11858
|
emit({ type: "phase", phase: "base" });
|
|
11629
|
-
const baseDir = writeVariant(PI_SURFACE, baseVariant,
|
|
11859
|
+
const baseDir = writeVariant(PI_SURFACE, baseVariant, join38(workDir, "variants", "base"));
|
|
11630
11860
|
const labels = Array.from({ length: k }, (_, i) => `base${i + 1}`);
|
|
11631
11861
|
const base = await mapLimit(labels, input.rolloutWidth ?? 4, async (label) => {
|
|
11632
11862
|
emit({ type: "rollout.started", label });
|
|
@@ -11635,7 +11865,7 @@ async function runRefinement(input) {
|
|
|
11635
11865
|
if (input.signal?.aborted) throw new Error("Refinement was cancelled.");
|
|
11636
11866
|
rollout = await executor.execute(task, baseDir, label, runIdOf(label));
|
|
11637
11867
|
} catch (error) {
|
|
11638
|
-
rollout = { label, runId: runIdOf(label), dir:
|
|
11868
|
+
rollout = { label, runId: runIdOf(label), dir: join38(workDir, "missing", label), ok: false, delivered: false, costUsd: 0, wallMs: 0, error: error instanceof Error ? error.message : String(error) };
|
|
11639
11869
|
}
|
|
11640
11870
|
emit({ type: "rollout.finished", label, ok: rollout.ok, delivered: rollout.delivered, error: rollout.error });
|
|
11641
11871
|
return rollout;
|
|
@@ -11804,7 +12034,7 @@ function ftsAny(query) {
|
|
|
11804
12034
|
}
|
|
11805
12035
|
return terms.length ? terms.join(" OR ") : null;
|
|
11806
12036
|
}
|
|
11807
|
-
function search2(root, query, scope,
|
|
12037
|
+
function search2(root, query, scope, limit2) {
|
|
11808
12038
|
const fts = ftsAny(query);
|
|
11809
12039
|
if (!fts) return [];
|
|
11810
12040
|
return withIndex(
|
|
@@ -11825,7 +12055,7 @@ function search2(root, query, scope, limit) {
|
|
|
11825
12055
|
scope.projectId ?? null,
|
|
11826
12056
|
scope.since ?? null,
|
|
11827
12057
|
scope.since ?? null,
|
|
11828
|
-
Math.min(Math.max(
|
|
12058
|
+
Math.min(Math.max(limit2, 1), SEARCH_MAX)
|
|
11829
12059
|
).map((row) => ({ runId: row.run_id, seq: Number(row.seq), role: row.role, at: row.at ?? "", mode: row.mode ?? "", sessionId: row.session_id ?? "", projectId: row.project_id, snippet: row.snippet }))
|
|
11830
12060
|
);
|
|
11831
12061
|
}
|
|
@@ -11883,8 +12113,8 @@ function searchTool2(env, context, params) {
|
|
|
11883
12113
|
if (!query) throw invalid("Give a query.");
|
|
11884
12114
|
const scope = callerScope(env.root, context, params);
|
|
11885
12115
|
const requested = params?.limit;
|
|
11886
|
-
const
|
|
11887
|
-
const hits = search2(env.root, query, scope,
|
|
12116
|
+
const limit2 = typeof requested === "number" && Number.isInteger(requested) && requested >= 0 ? requested : SEARCH_DEFAULT;
|
|
12117
|
+
const hits = search2(env.root, query, scope, limit2 + 4 + (context.recallExcludeAgents?.length ? SEARCH_MAX : 0)).filter((hit2) => hit2.runId !== context.runId && !excluded(env, context, hit2.sessionId)).slice(0, Math.min(Math.max(limit2, 1), SEARCH_MAX));
|
|
11888
12118
|
if (!hits.length) {
|
|
11889
12119
|
return scope.sessionId && !isSession(context) ? 'Nothing in your own conversations matches. Pass scope "all" to search every conversation and Harness run.' : "Nothing in the recorded history matches.";
|
|
11890
12120
|
}
|
|
@@ -12004,7 +12234,7 @@ function connectedAppServerMethods(harness) {
|
|
|
12004
12234
|
}
|
|
12005
12235
|
|
|
12006
12236
|
// src/tools/dispatch.ts
|
|
12007
|
-
import { existsSync as existsSync17, readdirSync as
|
|
12237
|
+
import { existsSync as existsSync17, readdirSync as readdirSync20, readFileSync as readFileSync20 } from "node:fs";
|
|
12008
12238
|
import { join as join40 } from "node:path";
|
|
12009
12239
|
init_errors();
|
|
12010
12240
|
|
|
@@ -12081,14 +12311,14 @@ function searchTool3(env, context, params) {
|
|
|
12081
12311
|
const status = textParam2(params, "status");
|
|
12082
12312
|
const since = dateValue(params, "since");
|
|
12083
12313
|
const until2 = dateValue(params, "until");
|
|
12084
|
-
const
|
|
12314
|
+
const limit2 = boundedInteger(params, "limit", SEARCH_DEFAULT2, 1, SEARCH_MAX2);
|
|
12085
12315
|
const cursor = decodeCursor(textParam2(params, "cursor"));
|
|
12086
12316
|
if (status && !runStatusSchema.safeParse(status).success) throw invalid(`Unknown run status ${status}.`);
|
|
12087
12317
|
const projects = listProjects(env.root);
|
|
12088
12318
|
const project = projectKey ? projects.find((entry2) => entry2.id === projectKey || entry2.slug === projectKey || entry2.name.toLowerCase() === projectKey.toLowerCase()) : null;
|
|
12089
12319
|
if (projectKey && !project) throw invalid(`There is no project called ${projectKey}.`);
|
|
12090
12320
|
const matching = readAllRuns(env.root).filter((run2) => !hidden(env, context, run2)).filter((run2) => !agent || run2.agentId === agent || run2.agentId !== null && env.directory.agentName(run2.agentId)?.toLowerCase() === agent.toLowerCase()).filter((run2) => !projectKey || run2.projectId === project?.id).filter((run2) => !mode2 || run2.mode === mode2).filter((run2) => !status || run2.status === status).filter((run2) => !since || Date.parse(run2.startedAt) >= since.timestamp).filter((run2) => !until2 || Date.parse(run2.startedAt) <= until2.timestamp).filter((run2) => !cursor || afterCursor(run2, cursor)).sort((left, right) => compareText(right.startedAt, left.startedAt) || compareText(right.id, left.id));
|
|
12091
|
-
const page2 = matching.slice(0,
|
|
12321
|
+
const page2 = matching.slice(0, limit2);
|
|
12092
12322
|
const hasMore = matching.length > page2.length;
|
|
12093
12323
|
return JSON.stringify({
|
|
12094
12324
|
runs: page2.map((run2) => summary2(env, run2, projects)),
|
|
@@ -12159,12 +12389,12 @@ function readTool2(env, context, params) {
|
|
|
12159
12389
|
const run2 = findRun(env.root, runId);
|
|
12160
12390
|
if (!run2 || hidden(env, context, run2)) throw notFound("Run");
|
|
12161
12391
|
const afterSequence = boundedInteger(params, "afterSequence", -1, -1, Number.MAX_SAFE_INTEGER);
|
|
12162
|
-
const
|
|
12392
|
+
const limit2 = boundedInteger(params, "limit", READ_DEFAULT, 1, READ_MAX);
|
|
12163
12393
|
const captured = snapshot(env.root, run2.id);
|
|
12164
12394
|
const candidates = captured.events.filter((event) => event.sequence > afterSequence);
|
|
12165
12395
|
const events2 = [];
|
|
12166
12396
|
let eventChars = 0;
|
|
12167
|
-
for (const event of candidates.slice(0,
|
|
12397
|
+
for (const event of candidates.slice(0, limit2)) {
|
|
12168
12398
|
const bounded4 = publicEvent(event);
|
|
12169
12399
|
const size2 = JSON.stringify(bounded4).length;
|
|
12170
12400
|
if (events2.length && eventChars + size2 > PAGE_MAX_CHARS) break;
|
|
@@ -12187,14 +12417,14 @@ function readTool2(env, context, params) {
|
|
|
12187
12417
|
// src/plugins/proposals.ts
|
|
12188
12418
|
init_errors();
|
|
12189
12419
|
import { createHash as createHash7, randomUUID as randomUUID5 } from "node:crypto";
|
|
12190
|
-
import { mkdirSync as mkdirSync15, readdirSync as
|
|
12191
|
-
import { dirname as
|
|
12420
|
+
import { mkdirSync as mkdirSync15, readdirSync as readdirSync19, renameSync as renameSync5, rmSync as rmSync15, rmdirSync as rmdirSync2, writeFileSync as writeFileSync6 } from "node:fs";
|
|
12421
|
+
import { dirname as dirname13, join as join39 } from "node:path";
|
|
12192
12422
|
init_fs();
|
|
12193
12423
|
var MAX_FILES2 = 100;
|
|
12194
12424
|
var MAX_FILE_BYTES = 256 * 1024;
|
|
12195
12425
|
var MAX_TOTAL_BYTES = 1024 * 1024;
|
|
12196
|
-
var dir = (root) =>
|
|
12197
|
-
var pathOf = (root, id) =>
|
|
12426
|
+
var dir = (root) => join39(root, "plugin-proposals");
|
|
12427
|
+
var pathOf = (root, id) => join39(dir(root), `${safeId(id)}.json`);
|
|
12198
12428
|
function validate2(name, description, input) {
|
|
12199
12429
|
if (typeof name !== "string" || !/^[a-z0-9][a-z0-9_-]{0,63}$/.test(name)) throw invalid("Plugin name must be lowercase letters, digits, underscores or hyphens.");
|
|
12200
12430
|
if (typeof description !== "string" || !description.trim() || Buffer.byteLength(description, "utf8") > 4096 || /[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/u.test(description)) throw invalid("Description must be non-empty valid text of at most 4096 bytes.");
|
|
@@ -12238,7 +12468,7 @@ function preview(root, id) {
|
|
|
12238
12468
|
function list4(root) {
|
|
12239
12469
|
let names2;
|
|
12240
12470
|
try {
|
|
12241
|
-
names2 =
|
|
12471
|
+
names2 = readdirSync19(dir(root));
|
|
12242
12472
|
} catch (error) {
|
|
12243
12473
|
if (error.code === "ENOENT") return [];
|
|
12244
12474
|
throw error;
|
|
@@ -12266,19 +12496,19 @@ async function accept(harness, id, hash) {
|
|
|
12266
12496
|
reviewed(proposal, hash);
|
|
12267
12497
|
const pluginId = `package:${proposal.name}`;
|
|
12268
12498
|
if (existing.some((plugin) => plugin.id === pluginId)) throw invalid("A plugin with this name already exists.");
|
|
12269
|
-
const parent =
|
|
12270
|
-
const destination =
|
|
12499
|
+
const parent = join39(root, "plugins");
|
|
12500
|
+
const destination = join39(parent, proposal.name);
|
|
12271
12501
|
mkdirSync15(parent, { recursive: true });
|
|
12272
|
-
const stage2 =
|
|
12502
|
+
const stage2 = join39(parent, `.proposal-${randomUUID5()}`);
|
|
12273
12503
|
mkdirSync15(stage2);
|
|
12274
12504
|
let reserved = false;
|
|
12275
12505
|
try {
|
|
12276
12506
|
for (const [path4, content] of Object.entries(proposal.files)) {
|
|
12277
|
-
const target =
|
|
12278
|
-
mkdirSync15(
|
|
12507
|
+
const target = join39(stage2, path4);
|
|
12508
|
+
mkdirSync15(dirname13(target), { recursive: true });
|
|
12279
12509
|
writeFileSync6(target, content, { flag: "wx" });
|
|
12280
12510
|
}
|
|
12281
|
-
writeFileSync6(
|
|
12511
|
+
writeFileSync6(join39(stage2, "package.json"), proposal.manifest, { flag: "wx" });
|
|
12282
12512
|
const found = { kind: "extension", path: stage2, origin: "package", project: false, packageRoot: stage2, source: stage2, enabled: true };
|
|
12283
12513
|
const code = packageCode([found]).get(stage2);
|
|
12284
12514
|
if (harness.plugins.trust.has(code.hash)) throw invalid("Identical package code is already trusted; change it before accepting.");
|
|
@@ -12308,24 +12538,6 @@ async function accept(harness, id, hash) {
|
|
|
12308
12538
|
}
|
|
12309
12539
|
}
|
|
12310
12540
|
|
|
12311
|
-
// src/tools/defaultSkills.ts
|
|
12312
|
-
import { existsSync as existsSync16 } from "node:fs";
|
|
12313
|
-
import { dirname as dirname13, join as join39 } from "node:path";
|
|
12314
|
-
import { fileURLToPath } from "node:url";
|
|
12315
|
-
function defaultSkillPath() {
|
|
12316
|
-
let dir2 = dirname13(fileURLToPath(import.meta.url));
|
|
12317
|
-
for (; ; ) {
|
|
12318
|
-
const path4 = join39(dir2, "builtin", "skills", "plugin-authoring", "SKILL.md");
|
|
12319
|
-
if (existsSync16(path4)) return path4;
|
|
12320
|
-
const parent = dirname13(dir2);
|
|
12321
|
-
if (parent === dir2) throw new Error("The bundled plugin-authoring skill is missing.");
|
|
12322
|
-
dir2 = parent;
|
|
12323
|
-
}
|
|
12324
|
-
}
|
|
12325
|
-
function defaultSkillPaths(variantDir) {
|
|
12326
|
-
return variantDir && existsSync16(join39(variantDir, "skills", "plugin-authoring", "SKILL.md")) ? [] : [defaultSkillPath()];
|
|
12327
|
-
}
|
|
12328
|
-
|
|
12329
12541
|
// src/tools/dispatch.ts
|
|
12330
12542
|
function str(params, key) {
|
|
12331
12543
|
const value = params[key];
|
|
@@ -12380,20 +12592,19 @@ ${tail}` : ""}`;
|
|
|
12380
12592
|
}
|
|
12381
12593
|
}
|
|
12382
12594
|
function loadSkill(variantDir, name) {
|
|
12383
|
-
const skills = variantDir && existsSync17(join40(variantDir, "skills")) ?
|
|
12384
|
-
|
|
12385
|
-
if (defaults.length) skills.push("plugin-authoring");
|
|
12595
|
+
const skills = variantDir && existsSync17(join40(variantDir, "skills")) ? readdirSync20(join40(variantDir, "skills"), { withFileTypes: true }).filter((entry2) => entry2.isDirectory() && existsSync17(join40(variantDir, "skills", entry2.name, "SKILL.md"))).map((entry2) => entry2.name).sort() : [];
|
|
12596
|
+
if (!skills.includes("plugin-authoring") && defaultSkillPaths(variantDir).length) skills.push("plugin-authoring");
|
|
12386
12597
|
skills.sort();
|
|
12387
12598
|
const wanted = name.trim().replace(/^skills\//, "").replace(/`/g, "");
|
|
12388
12599
|
if (!wanted) return skills.length ? `Your skills: ${skills.join(", ")}. Load one with skill_load and its name.` : "You have no skills.";
|
|
12389
|
-
if (
|
|
12600
|
+
if (!SKILL_NAME.test(wanted)) throw invalid("A skill name is lowercase letters, digits, _ or -.");
|
|
12390
12601
|
if (!skills.includes(wanted)) return `There is no skill named ${wanted}.${skills.length ? ` Your skills: ${skills.join(", ")}.` : ""}`;
|
|
12391
|
-
|
|
12392
|
-
|
|
12393
|
-
const
|
|
12394
|
-
return `${readFileSync19(join40(dir2, "SKILL.md"), "utf8")}${helpers.length ? `
|
|
12602
|
+
const skill = readSkillFile(variantDir, wanted);
|
|
12603
|
+
if (!skill) return `There is no skill named ${wanted}.${skills.length ? ` Your skills: ${skills.join(", ")}.` : ""}`;
|
|
12604
|
+
const helperNote = skill.helpers.length ? `
|
|
12395
12605
|
|
|
12396
|
-
(This skill's helpers are in ${join40(
|
|
12606
|
+
(This skill's helpers are in ${join40(skill.baseDir, "scripts")}: ${skill.helpers.join(", ")}.)` : "";
|
|
12607
|
+
return `${readFileSync20(skill.path, "utf8")}${helperNote}`;
|
|
12397
12608
|
}
|
|
12398
12609
|
|
|
12399
12610
|
// src/tools/harnessTools.ts
|
|
@@ -12592,6 +12803,7 @@ var VARIANT_PLUGIN = {
|
|
|
12592
12803
|
{ id: "memory", name: "Memory", description: "c3: durable facts about this kind of work." },
|
|
12593
12804
|
{ id: "subagents", name: "Subagents", description: "c5: the list of this variant's subagents." },
|
|
12594
12805
|
{ id: "scripts", name: "Scripts", description: "c7: where this variant's scripts are." },
|
|
12806
|
+
{ id: "required-skills", name: "Required skills", description: "Skills the person named as required for one request." },
|
|
12595
12807
|
{ id: "reporting", name: "Reporting", description: "Fixed foundation text, not part of the variant: how the final reply is shaped." }
|
|
12596
12808
|
],
|
|
12597
12809
|
tools: tools3(SKILL_TOOLS)
|
|
@@ -12718,7 +12930,7 @@ var HARNESS_PLUGINS = BUILTIN_PLUGIN_REGISTRY.descriptors();
|
|
|
12718
12930
|
var size = (path4) => {
|
|
12719
12931
|
if (!path4) return null;
|
|
12720
12932
|
try {
|
|
12721
|
-
return charCount(
|
|
12933
|
+
return charCount(readFileSync21(path4, "utf8"));
|
|
12722
12934
|
} catch {
|
|
12723
12935
|
return null;
|
|
12724
12936
|
}
|
|
@@ -12903,7 +13115,7 @@ function forgetAgent(harness, agentId) {
|
|
|
12903
13115
|
}
|
|
12904
13116
|
|
|
12905
13117
|
// src/plugins/install.ts
|
|
12906
|
-
import { existsSync as existsSync18, mkdirSync as mkdirSync16, renameSync as renameSync6, statSync as
|
|
13118
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync16, renameSync as renameSync6, statSync as statSync11 } from "node:fs";
|
|
12907
13119
|
import { homedir as homedir4 } from "node:os";
|
|
12908
13120
|
import { basename as basename8, isAbsolute as isAbsolute5, join as join42, resolve as resolve5 } from "node:path";
|
|
12909
13121
|
init_errors();
|
|
@@ -12925,7 +13137,7 @@ async function manager(harness) {
|
|
|
12925
13137
|
var changed = (harness) => harness.bus.emit({ type: "plugins.changed" });
|
|
12926
13138
|
async function install(harness, params) {
|
|
12927
13139
|
const source = normalizeSource(params.source);
|
|
12928
|
-
if (isAbsolute5(source) && !(existsSync18(source) &&
|
|
13140
|
+
if (isAbsolute5(source) && !(existsSync18(source) && statSync11(source).isDirectory())) throw invalid("That folder does not exist.");
|
|
12929
13141
|
await ensureAdopted(harness);
|
|
12930
13142
|
const before = new Set((await list3(harness, params)).map((plugin) => plugin.id));
|
|
12931
13143
|
const { settings, packages } = await manager(harness);
|
|
@@ -13001,7 +13213,7 @@ async function update2(harness, params) {
|
|
|
13001
13213
|
|
|
13002
13214
|
// src/variant/components.ts
|
|
13003
13215
|
init_errors();
|
|
13004
|
-
import { lstatSync as lstatSync7, mkdirSync as mkdirSync17, mkdtempSync as mkdtempSync3, readdirSync as
|
|
13216
|
+
import { lstatSync as lstatSync7, mkdirSync as mkdirSync17, mkdtempSync as mkdtempSync3, readdirSync as readdirSync21, readFileSync as readFileSync22, renameSync as renameSync7, rmSync as rmSync16, writeFileSync as writeFileSync7 } from "node:fs";
|
|
13005
13217
|
import { basename as basename9, dirname as dirname14, join as join43 } from "node:path";
|
|
13006
13218
|
init_fs();
|
|
13007
13219
|
var KINDS = ["skills", "prompts", "rules"];
|
|
@@ -13016,7 +13228,7 @@ var kindDir = (root, kind) => join43(root, "registry", kind);
|
|
|
13016
13228
|
function itemFrom(kind, stem, file2) {
|
|
13017
13229
|
let text10;
|
|
13018
13230
|
try {
|
|
13019
|
-
text10 =
|
|
13231
|
+
text10 = readFileSync22(file2, "utf8");
|
|
13020
13232
|
} catch {
|
|
13021
13233
|
return null;
|
|
13022
13234
|
}
|
|
@@ -13039,7 +13251,7 @@ function itemsIn(directory) {
|
|
|
13039
13251
|
for (const kind of KINDS) {
|
|
13040
13252
|
let names2;
|
|
13041
13253
|
try {
|
|
13042
|
-
names2 =
|
|
13254
|
+
names2 = readdirSync21(join43(directory, kind));
|
|
13043
13255
|
} catch {
|
|
13044
13256
|
continue;
|
|
13045
13257
|
}
|
|
@@ -13069,7 +13281,7 @@ function isInVariant(root, variant, id) {
|
|
|
13069
13281
|
if (!item) return false;
|
|
13070
13282
|
if (item.kind === "skills") return variant["skills/" + skillName(item) + "/SKILL.md"] !== void 0;
|
|
13071
13283
|
if (item.kind === "rules") {
|
|
13072
|
-
const text10 =
|
|
13284
|
+
const text10 = readFileSync22(item.path, "utf8");
|
|
13073
13285
|
const body2 = (parse(text10)?.body ?? text10).trim();
|
|
13074
13286
|
return Boolean(body2) && (variant[GUARDRAILS] ?? "").includes(body2);
|
|
13075
13287
|
}
|
|
@@ -13079,7 +13291,7 @@ function addToVariant(root, variant, id) {
|
|
|
13079
13291
|
const item = list5(root).find((candidate) => candidate.id === id);
|
|
13080
13292
|
if (!item) throw notFound("That library item");
|
|
13081
13293
|
const next = { ...variant };
|
|
13082
|
-
const text10 =
|
|
13294
|
+
const text10 = readFileSync22(item.path, "utf8");
|
|
13083
13295
|
const body2 = (parse(text10)?.body ?? text10).trim();
|
|
13084
13296
|
if (item.kind === "rules") {
|
|
13085
13297
|
const current2 = (next[GUARDRAILS] ?? "").trimEnd();
|
|
@@ -13099,7 +13311,7 @@ ${body2}
|
|
|
13099
13311
|
`;
|
|
13100
13312
|
const folder2 = dirname14(item.path);
|
|
13101
13313
|
if (basename9(item.path) === "SKILL.md" && isDir(join43(folder2, "scripts"))) {
|
|
13102
|
-
for (const file2 of
|
|
13314
|
+
for (const file2 of readdirSync21(join43(folder2, "scripts"))) next[`skills/${name}/scripts/${file2}`] = readFileSync22(join43(folder2, "scripts", file2), "utf8");
|
|
13103
13315
|
}
|
|
13104
13316
|
autotrigger(PI_SURFACE, next);
|
|
13105
13317
|
return next;
|
|
@@ -13419,7 +13631,7 @@ function acquire(path4) {
|
|
|
13419
13631
|
throw new HarnessError("hub_busy", "Another installation is using this library. Wait and retry.");
|
|
13420
13632
|
}
|
|
13421
13633
|
try {
|
|
13422
|
-
const pid = Number(
|
|
13634
|
+
const pid = Number(readFileSync23(path4, "utf8"));
|
|
13423
13635
|
if (Number.isInteger(pid) && pid > 0) {
|
|
13424
13636
|
try {
|
|
13425
13637
|
process.kill(pid, 0);
|
|
@@ -13478,7 +13690,7 @@ var Hub = class {
|
|
|
13478
13690
|
const path4 = join44(this.harness.dataRoot, "hub", "documents", receipt.document);
|
|
13479
13691
|
const stat = lstatSync8(path4);
|
|
13480
13692
|
if (!stat.isFile() || stat.size > HUB_MAX_BYTES) return "incomplete";
|
|
13481
|
-
return digest(
|
|
13693
|
+
return digest(readFileSync23(path4)) === receipt.entry.delivery.sha256 ? "installed" : "changed";
|
|
13482
13694
|
} catch {
|
|
13483
13695
|
return "incomplete";
|
|
13484
13696
|
}
|
|
@@ -13493,7 +13705,7 @@ var Hub = class {
|
|
|
13493
13705
|
if (receipt.entry.delivery.kind !== "document" || receipt.document !== `${receiptName(receipt.entry)}.json`) return false;
|
|
13494
13706
|
const path4 = join44(root, "hub", "documents", receipt.document);
|
|
13495
13707
|
const stat = lstatSync8(path4);
|
|
13496
|
-
return stat.isFile() && stat.size <= HUB_MAX_BYTES && digest(
|
|
13708
|
+
return stat.isFile() && stat.size <= HUB_MAX_BYTES && digest(readFileSync23(path4)) === receipt.entry.delivery.sha256;
|
|
13497
13709
|
}
|
|
13498
13710
|
if (receipt.entry.delivery.kind === "registry") return receipt.resourceIds.length > 0 && receipt.resourceIds.every((id) => {
|
|
13499
13711
|
if (!/^(skills|prompts|rules)\/[a-z0-9-]{1,64}$/.test(id)) return false;
|
|
@@ -13772,7 +13984,7 @@ var Hub = class {
|
|
|
13772
13984
|
const path4 = join44(this.harness.env.root, "hub", "documents", receipt.document);
|
|
13773
13985
|
const stat = lstatSync8(path4);
|
|
13774
13986
|
if (!stat.isFile() || stat.size > HUB_MAX_BYTES) throw invalid("The saved document is not a bounded regular file.");
|
|
13775
|
-
const content =
|
|
13987
|
+
const content = readFileSync23(path4, "utf8");
|
|
13776
13988
|
if (receipt.entry.delivery.kind === "pi-package" || digest(content) !== receipt.entry.delivery.sha256) throw invalid("The saved document differs from the installed version. Import edited files explicitly instead.");
|
|
13777
13989
|
return { entry: receipt.entry, content };
|
|
13778
13990
|
}
|
|
@@ -14253,8 +14465,8 @@ function pageTools(tools4, options2 = {}) {
|
|
|
14253
14465
|
const query = options2.query?.trim().toLowerCase();
|
|
14254
14466
|
const matching = query ? tools4.filter((tool) => tool.name.toLowerCase().includes(query) || (tool.description ?? "").toLowerCase().includes(query)) : tools4;
|
|
14255
14467
|
const offset = Math.max(0, Math.floor(options2.offset ?? 0));
|
|
14256
|
-
const
|
|
14257
|
-
const page2 = compactTools(matching.slice(offset, offset +
|
|
14468
|
+
const limit2 = Math.max(1, Math.min(Math.floor(options2.limit ?? TOOL_PAGE), 100));
|
|
14469
|
+
const page2 = compactTools(matching.slice(offset, offset + limit2));
|
|
14258
14470
|
const next = offset + page2.length;
|
|
14259
14471
|
return { tools: page2, total: matching.length, ...next < matching.length ? { more: matching.length - next, nextOffset: next } : {} };
|
|
14260
14472
|
}
|
|
@@ -14681,19 +14893,19 @@ ${action}`, standing: "switch", timeoutMs: 3e5 });
|
|
|
14681
14893
|
};
|
|
14682
14894
|
|
|
14683
14895
|
// src/history/lessons.ts
|
|
14684
|
-
import { mkdtempSync as mkdtempSync7, readFileSync as
|
|
14896
|
+
import { mkdtempSync as mkdtempSync7, readFileSync as readFileSync26, rmSync as rmSync20, writeFileSync as writeFileSync10 } from "node:fs";
|
|
14685
14897
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
14686
14898
|
import { join as join48 } from "node:path";
|
|
14687
14899
|
|
|
14688
14900
|
// src/refine/pi.ts
|
|
14689
14901
|
init_fs();
|
|
14690
14902
|
import { createHash as createHash10, randomUUID as randomUUID9 } from "node:crypto";
|
|
14691
|
-
import { cpSync as cpSync4, existsSync as existsSync20, mkdirSync as mkdirSync19, mkdtempSync as mkdtempSync6, readFileSync as
|
|
14903
|
+
import { cpSync as cpSync4, existsSync as existsSync20, mkdirSync as mkdirSync19, mkdtempSync as mkdtempSync6, readFileSync as readFileSync25, rmSync as rmSync19, writeFileSync as writeFileSync9 } from "node:fs";
|
|
14692
14904
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
14693
14905
|
import { dirname as dirname15, join as join47 } from "node:path";
|
|
14694
14906
|
|
|
14695
14907
|
// src/refine/host.ts
|
|
14696
|
-
import { cpSync as cpSync3, existsSync as existsSync19, mkdtempSync as mkdtempSync5, readdirSync as
|
|
14908
|
+
import { cpSync as cpSync3, existsSync as existsSync19, mkdtempSync as mkdtempSync5, readdirSync as readdirSync22, readFileSync as readFileSync24, rmSync as rmSync18, statSync as statSync12 } from "node:fs";
|
|
14697
14909
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
14698
14910
|
import { join as join46, relative as relative6, sep as sep8 } from "node:path";
|
|
14699
14911
|
var TEXT_LIMIT = 2e5;
|
|
@@ -14701,7 +14913,7 @@ var FILES_LIMIT = 40;
|
|
|
14701
14913
|
function files2(dir2, into = [], base = dir2) {
|
|
14702
14914
|
let names2;
|
|
14703
14915
|
try {
|
|
14704
|
-
names2 =
|
|
14916
|
+
names2 = readdirSync22(dir2);
|
|
14705
14917
|
} catch {
|
|
14706
14918
|
return into;
|
|
14707
14919
|
}
|
|
@@ -14709,7 +14921,7 @@ function files2(dir2, into = [], base = dir2) {
|
|
|
14709
14921
|
if (name === ".git" || name === "node_modules" || name.startsWith(".")) continue;
|
|
14710
14922
|
const path4 = join46(dir2, name);
|
|
14711
14923
|
try {
|
|
14712
|
-
if (
|
|
14924
|
+
if (statSync12(path4).isDirectory()) files2(path4, into, base);
|
|
14713
14925
|
else into.push(relative6(base, path4).split(sep8).join("/"));
|
|
14714
14926
|
} catch {
|
|
14715
14927
|
}
|
|
@@ -14719,7 +14931,7 @@ function files2(dir2, into = [], base = dir2) {
|
|
|
14719
14931
|
}
|
|
14720
14932
|
function readable(path4) {
|
|
14721
14933
|
try {
|
|
14722
|
-
const buffer =
|
|
14934
|
+
const buffer = readFileSync24(path4);
|
|
14723
14935
|
if (buffer.length > TEXT_LIMIT || buffer.includes(0)) return null;
|
|
14724
14936
|
return buffer.toString("utf8");
|
|
14725
14937
|
} catch {
|
|
@@ -14753,9 +14965,9 @@ var DEFAULT_REFINE_HOST = {
|
|
|
14753
14965
|
|
|
14754
14966
|
// src/refine/trajectory.ts
|
|
14755
14967
|
var TRUNC = (n) => `\u2026(+${n} chars \u2014 render truncation)`;
|
|
14756
|
-
function clip4(text10,
|
|
14968
|
+
function clip4(text10, limit2) {
|
|
14757
14969
|
const clean2 = text10.replace(/\0/g, "");
|
|
14758
|
-
return
|
|
14970
|
+
return limit2 > 0 && clean2.length > limit2 ? `${clean2.slice(0, limit2)}${TRUNC(clean2.length - limit2)}` : clean2;
|
|
14759
14971
|
}
|
|
14760
14972
|
function renderEvents(events2, options2) {
|
|
14761
14973
|
const out = [];
|
|
@@ -14947,7 +15159,7 @@ var PiExecutor = class {
|
|
|
14947
15159
|
const out = {};
|
|
14948
15160
|
for (const name of record3.files ?? []) {
|
|
14949
15161
|
try {
|
|
14950
|
-
out[name] =
|
|
15162
|
+
out[name] = readFileSync25(join47(rollout.dir, "deliverables", name), "utf8");
|
|
14951
15163
|
} catch {
|
|
14952
15164
|
}
|
|
14953
15165
|
}
|
|
@@ -15047,7 +15259,7 @@ var slug2 = (text10) => text10.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace
|
|
|
15047
15259
|
function keptLessons(root) {
|
|
15048
15260
|
return paths(root).filter((path4) => path4.startsWith(`${LESSONS_FOLDER}/`)).flatMap((path4) => {
|
|
15049
15261
|
try {
|
|
15050
|
-
const text10 =
|
|
15262
|
+
const text10 = readFileSync26(join48(wikiDir(root), `${path4}.md`), "utf8");
|
|
15051
15263
|
const parsed = parse(text10);
|
|
15052
15264
|
const front = parsed?.front ?? {};
|
|
15053
15265
|
const sources = Array.isArray(front.sources) ? front.sources.filter((id) => typeof id === "string") : [];
|
|
@@ -15175,7 +15387,7 @@ ${run2.goal}
|
|
|
15175
15387
|
init_errors();
|
|
15176
15388
|
init_fs();
|
|
15177
15389
|
import { randomUUID as randomUUID10 } from "node:crypto";
|
|
15178
|
-
import { existsSync as existsSync21, readdirSync as
|
|
15390
|
+
import { existsSync as existsSync21, readdirSync as readdirSync23 } from "node:fs";
|
|
15179
15391
|
import { join as join49 } from "node:path";
|
|
15180
15392
|
var variantsFolder = (dir2) => existsSync21(join49(dir2, "variants")) || !existsSync21(join49(dir2, "harnesses")) ? join49(dir2, "variants") : join49(dir2, "harnesses");
|
|
15181
15393
|
var Refinements = class {
|
|
@@ -15231,7 +15443,7 @@ var Refinements = class {
|
|
|
15231
15443
|
const dir2 = join49(this.options.root(), "refine");
|
|
15232
15444
|
if (!existsSync21(dir2)) return [];
|
|
15233
15445
|
const out = [];
|
|
15234
|
-
for (const name of
|
|
15446
|
+
for (const name of readdirSync23(dir2).sort().reverse()) {
|
|
15235
15447
|
if (name === "library") continue;
|
|
15236
15448
|
const summary4 = readSummary(this.options.root(), name);
|
|
15237
15449
|
if (summary4 && (!options2.scope || summary4.scope === options2.scope)) out.push(summary4);
|
|
@@ -15251,7 +15463,7 @@ var Refinements = class {
|
|
|
15251
15463
|
const dir2 = refineDir(root, id);
|
|
15252
15464
|
const baseVariant = readVariant(PI_SURFACE, join49(variantsFolder(dir2), "base"));
|
|
15253
15465
|
const finals = new Set(summary4.recursion?.finals ?? []);
|
|
15254
|
-
const labels = existsSync21(join49(dir2, "rollouts")) ?
|
|
15466
|
+
const labels = existsSync21(join49(dir2, "rollouts")) ? readdirSync23(join49(dir2, "rollouts")).sort() : [];
|
|
15255
15467
|
return labels.map((label) => {
|
|
15256
15468
|
const record3 = readJsonOr(join49(dir2, "rollouts", label, "rollout.json"), {});
|
|
15257
15469
|
const base = summary4.base.find((entry2) => entry2.label === label);
|
|
@@ -15310,7 +15522,7 @@ var Refinements = class {
|
|
|
15310
15522
|
};
|
|
15311
15523
|
|
|
15312
15524
|
// src/variant/migrate.ts
|
|
15313
|
-
import { existsSync as existsSync22, readdirSync as
|
|
15525
|
+
import { existsSync as existsSync22, readdirSync as readdirSync24, renameSync as renameSync9 } from "node:fs";
|
|
15314
15526
|
import { join as join50 } from "node:path";
|
|
15315
15527
|
function move(from, to, moved) {
|
|
15316
15528
|
if (!existsSync22(from) || existsSync22(to)) return;
|
|
@@ -15319,7 +15531,7 @@ function move(from, to, moved) {
|
|
|
15319
15531
|
}
|
|
15320
15532
|
function folders(path4) {
|
|
15321
15533
|
try {
|
|
15322
|
-
return
|
|
15534
|
+
return readdirSync24(path4, { withFileTypes: true }).filter((entry2) => entry2.isDirectory()).map((entry2) => entry2.name);
|
|
15323
15535
|
} catch {
|
|
15324
15536
|
return [];
|
|
15325
15537
|
}
|
|
@@ -15657,11 +15869,11 @@ var Doctor = class {
|
|
|
15657
15869
|
|
|
15658
15870
|
// src/doctor/checks.ts
|
|
15659
15871
|
import { randomUUID as randomUUID14 } from "node:crypto";
|
|
15660
|
-
import { accessSync as accessSync5, constants as constants6, existsSync as existsSync27, readFileSync as
|
|
15661
|
-
import { basename as basename12, delimiter as delimiter2, isAbsolute as isAbsolute8, join as
|
|
15872
|
+
import { accessSync as accessSync5, constants as constants6, existsSync as existsSync27, readFileSync as readFileSync30, statSync as statSync20 } from "node:fs";
|
|
15873
|
+
import { basename as basename12, delimiter as delimiter2, isAbsolute as isAbsolute8, join as join60 } from "node:path";
|
|
15662
15874
|
|
|
15663
15875
|
// src/core/shell.ts
|
|
15664
|
-
import { accessSync as accessSync3, constants as constants3, statSync as
|
|
15876
|
+
import { accessSync as accessSync3, constants as constants3, statSync as statSync13 } from "node:fs";
|
|
15665
15877
|
import { win32 } from "node:path";
|
|
15666
15878
|
var POWERSHELL_ARGS = ["-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-Command"];
|
|
15667
15879
|
var POWERSHELL_UTF8 = "try { [Console]::OutputEncoding=[System.Text.Encoding]::UTF8 } catch {}\n";
|
|
@@ -15708,7 +15920,7 @@ function isWslLauncher(path4, env) {
|
|
|
15708
15920
|
function isFile(path4) {
|
|
15709
15921
|
try {
|
|
15710
15922
|
accessSync3(path4, constants3.F_OK);
|
|
15711
|
-
return
|
|
15923
|
+
return statSync13(path4).isFile();
|
|
15712
15924
|
} catch {
|
|
15713
15925
|
return false;
|
|
15714
15926
|
}
|
|
@@ -15718,19 +15930,19 @@ function isFile(path4) {
|
|
|
15718
15930
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
15719
15931
|
import { spawn as spawn2 } from "node:child_process";
|
|
15720
15932
|
import { randomUUID as randomUUID12 } from "node:crypto";
|
|
15721
|
-
import { accessSync as accessSync4, constants as constants4, existsSync as existsSync24, lstatSync as lstatSync11, mkdtempSync as mkdtempSync8, realpathSync as realpathSync4, readdirSync as
|
|
15933
|
+
import { accessSync as accessSync4, constants as constants4, existsSync as existsSync24, lstatSync as lstatSync11, mkdtempSync as mkdtempSync8, realpathSync as realpathSync4, readdirSync as readdirSync25, rmSync as rmSync21, statSync as statSync15 } from "node:fs";
|
|
15722
15934
|
import { tmpdir as tmpdir6 } from "node:os";
|
|
15723
15935
|
import { join as join53 } from "node:path";
|
|
15724
15936
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
15725
15937
|
|
|
15726
15938
|
// src/core/workspace.ts
|
|
15727
15939
|
init_errors();
|
|
15728
|
-
import { lstatSync as lstatSync10, realpathSync as realpathSync3, statSync as
|
|
15940
|
+
import { lstatSync as lstatSync10, realpathSync as realpathSync3, statSync as statSync14 } from "node:fs";
|
|
15729
15941
|
import { homedir as homedir5 } from "node:os";
|
|
15730
15942
|
import { basename as basename10, dirname as dirname16, isAbsolute as isAbsolute7, join as join52, relative as relative7, resolve as resolve8, sep as sep9 } from "node:path";
|
|
15731
15943
|
function resolveWorkspaceRoot(cwd) {
|
|
15732
15944
|
const canonicalCwd = realpathSync3(cwd);
|
|
15733
|
-
if (!
|
|
15945
|
+
if (!statSync14(canonicalCwd).isDirectory()) throw invalid("The working directory must be a directory.");
|
|
15734
15946
|
if (dirname16(canonicalCwd) === canonicalCwd) throw invalid("The filesystem root cannot be used as an active project workspace.");
|
|
15735
15947
|
let directory = canonicalCwd;
|
|
15736
15948
|
while (true) {
|
|
@@ -15752,14 +15964,14 @@ function resolveWritePath(candidate, cwd = process.cwd()) {
|
|
|
15752
15964
|
}
|
|
15753
15965
|
function isWithinWorkspace(workspaceRoot, canonicalCandidate) {
|
|
15754
15966
|
const canonicalRoot = realpathSync3(workspaceRoot);
|
|
15755
|
-
if (!
|
|
15967
|
+
if (!statSync14(canonicalRoot).isDirectory()) throw invalid("The workspace root must be a directory.");
|
|
15756
15968
|
const fromRoot = relative7(canonicalRoot, canonicalCandidate);
|
|
15757
15969
|
return fromRoot === "" || fromRoot !== ".." && !fromRoot.startsWith(`..${sep9}`) && !isAbsolute7(fromRoot);
|
|
15758
15970
|
}
|
|
15759
15971
|
function verifyWorkspaceRoot(workspaceRoot) {
|
|
15760
15972
|
const canonicalRoot = realpathSync3(workspaceRoot);
|
|
15761
15973
|
if (dirname16(canonicalRoot) === canonicalRoot) throw invalid("The filesystem root cannot be used as an active project workspace.");
|
|
15762
|
-
if (canonicalRoot !== resolve8(workspaceRoot) || !
|
|
15974
|
+
if (canonicalRoot !== resolve8(workspaceRoot) || !statSync14(canonicalRoot).isDirectory()) {
|
|
15763
15975
|
throw invalid("The active project workspace changed after this run began.");
|
|
15764
15976
|
}
|
|
15765
15977
|
return canonicalRoot;
|
|
@@ -15802,7 +16014,7 @@ function systemExecutable(candidates) {
|
|
|
15802
16014
|
for (const candidate of candidates) {
|
|
15803
16015
|
try {
|
|
15804
16016
|
accessSync4(candidate, constants4.X_OK);
|
|
15805
|
-
if (
|
|
16017
|
+
if (statSync15(candidate).isFile()) return candidate;
|
|
15806
16018
|
} catch {
|
|
15807
16019
|
}
|
|
15808
16020
|
}
|
|
@@ -16023,7 +16235,7 @@ function assertNoExternalHardlinks(workspaceRoot) {
|
|
|
16023
16235
|
const visit = (directory) => {
|
|
16024
16236
|
let entries2;
|
|
16025
16237
|
try {
|
|
16026
|
-
entries2 =
|
|
16238
|
+
entries2 = readdirSync25(directory, { withFileTypes: true });
|
|
16027
16239
|
} catch (error) {
|
|
16028
16240
|
throw new Error(`Workspace hard-link inspection failed at ${directory}; Bash was not run: ${error instanceof Error ? error.message : String(error)}`);
|
|
16029
16241
|
}
|
|
@@ -16110,8 +16322,8 @@ function createWorkspaceBashOperations(workspaceRoot, options2 = {}) {
|
|
|
16110
16322
|
}
|
|
16111
16323
|
|
|
16112
16324
|
// src/terminal/terminals.ts
|
|
16113
|
-
import { chmodSync as chmodSync11, existsSync as existsSync26, lstatSync as lstatSync13, mkdirSync as mkdirSync22, readFileSync as
|
|
16114
|
-
import { dirname as dirname20, join as
|
|
16325
|
+
import { chmodSync as chmodSync11, existsSync as existsSync26, lstatSync as lstatSync13, mkdirSync as mkdirSync22, readFileSync as readFileSync29, unlinkSync as unlinkSync5, writeFileSync as writeFileSync11 } from "node:fs";
|
|
16326
|
+
import { dirname as dirname20, join as join59 } from "node:path";
|
|
16115
16327
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
16116
16328
|
import { Type as Type2 } from "typebox";
|
|
16117
16329
|
init_errors();
|
|
@@ -16201,6 +16413,239 @@ function withWorkspaceWriteScope(tool, note = "") {
|
|
|
16201
16413
|
};
|
|
16202
16414
|
}
|
|
16203
16415
|
|
|
16416
|
+
// src/context/attribution.ts
|
|
16417
|
+
import { readdirSync as readdirSync26, statSync as statSync16 } from "node:fs";
|
|
16418
|
+
import { join as join54 } from "node:path";
|
|
16419
|
+
var CHARS_PER_TOKEN = 4;
|
|
16420
|
+
function tokensOf(chars) {
|
|
16421
|
+
return Math.max(0, Math.ceil(chars / CHARS_PER_TOKEN));
|
|
16422
|
+
}
|
|
16423
|
+
var HARNESS_TOOL_GROUPS = /* @__PURE__ */ new Set(["History", "Wiki", "Native", "World", "Progress", "Session", "Annotations"]);
|
|
16424
|
+
var FOUNDATION_SECTIONS = /* @__PURE__ */ new Set(["harness-identity", "tools", "reporting"]);
|
|
16425
|
+
var DYNAMIC_SECTIONS = /* @__PURE__ */ new Set(["wiki", "session-state", "references", "required-skills"]);
|
|
16426
|
+
var GROUP_ORDER2 = ["foundation", "variant", "application", "conversation", "reserved"];
|
|
16427
|
+
function lastEvent(events2, type) {
|
|
16428
|
+
for (let index = events2.length - 1; index >= 0; index -= 1) {
|
|
16429
|
+
const event = events2[index];
|
|
16430
|
+
if (event?.type === type) return event.payload;
|
|
16431
|
+
}
|
|
16432
|
+
return null;
|
|
16433
|
+
}
|
|
16434
|
+
function sectionGroup(section2, dynamic) {
|
|
16435
|
+
if (dynamic.has(section2.id)) return "conversation";
|
|
16436
|
+
if (section2.sources.some((source) => source.kind === "variant")) return "variant";
|
|
16437
|
+
return FOUNDATION_SECTIONS.has(section2.id) ? "foundation" : "application";
|
|
16438
|
+
}
|
|
16439
|
+
function toolChars(tool) {
|
|
16440
|
+
try {
|
|
16441
|
+
return JSON.stringify({ name: tool.name, description: tool.description, parameters: tool.parameters }).length;
|
|
16442
|
+
} catch {
|
|
16443
|
+
return tool.name.length + tool.description.length;
|
|
16444
|
+
}
|
|
16445
|
+
}
|
|
16446
|
+
function shareOf(tokens, window) {
|
|
16447
|
+
if (!window) return null;
|
|
16448
|
+
return Math.max(0, Math.min(100, tokens / window * 100));
|
|
16449
|
+
}
|
|
16450
|
+
function skillCost(paths2) {
|
|
16451
|
+
const sizes = [];
|
|
16452
|
+
for (const path4 of paths2) {
|
|
16453
|
+
let entries2;
|
|
16454
|
+
try {
|
|
16455
|
+
entries2 = readdirSync26(path4);
|
|
16456
|
+
} catch {
|
|
16457
|
+
continue;
|
|
16458
|
+
}
|
|
16459
|
+
for (const entry2 of entries2) {
|
|
16460
|
+
try {
|
|
16461
|
+
const stat = statSync16(join54(path4, entry2, "SKILL.md"));
|
|
16462
|
+
if (stat.isFile()) sizes.push(stat.size);
|
|
16463
|
+
} catch {
|
|
16464
|
+
}
|
|
16465
|
+
}
|
|
16466
|
+
}
|
|
16467
|
+
if (!sizes.length) return null;
|
|
16468
|
+
const average = sizes.reduce((sum, size2) => sum + size2, 0) / sizes.length;
|
|
16469
|
+
return { items: sizes.length, tokensEach: tokensOf(average) };
|
|
16470
|
+
}
|
|
16471
|
+
function onDemandOf(env, pack) {
|
|
16472
|
+
const scope = pack.variant?.scope;
|
|
16473
|
+
if (!scope) return [];
|
|
16474
|
+
let built;
|
|
16475
|
+
try {
|
|
16476
|
+
built = materialise(env.root, { scope });
|
|
16477
|
+
} catch {
|
|
16478
|
+
return [];
|
|
16479
|
+
}
|
|
16480
|
+
const rows = [];
|
|
16481
|
+
const skills = skillCost(built.skillPaths);
|
|
16482
|
+
if (skills) rows.push({ id: "skills", title: "Skills (c6)", items: skills.items, tokensEach: skills.tokensEach, note: "loaded when a situation matches" });
|
|
16483
|
+
if (built.subagents.length) rows.push({ id: "subagents", title: "Subagents (c5)", items: built.subagents.length, tokensEach: null, note: "each runs in its own context" });
|
|
16484
|
+
const scripts = Object.keys(built.files).filter((path4) => path4.startsWith("scripts/") && !path4.endsWith("README.md"));
|
|
16485
|
+
if (scripts.length) rows.push({ id: "scripts", title: "Scripts (c7)", items: scripts.length, tokensEach: null, note: "run, not read into context" });
|
|
16486
|
+
return rows;
|
|
16487
|
+
}
|
|
16488
|
+
function attribution(env, runId) {
|
|
16489
|
+
const pack = load2(env.root, runId);
|
|
16490
|
+
if (!pack) return null;
|
|
16491
|
+
const events2 = readEvents(env.root, runId);
|
|
16492
|
+
const snapshot2 = lastEvent(events2, "context.snapshot");
|
|
16493
|
+
const usage = lastEvent(events2, "usage.updated");
|
|
16494
|
+
const sizes = pack.delivery?.sizes;
|
|
16495
|
+
const updatedIds = pack.delivery?.updatedSectionIds ?? [];
|
|
16496
|
+
const dynamic = pack.delivery ? new Set(updatedIds) : new Set([...DYNAMIC_SECTIONS].filter((id) => pack.sections.some((section2) => section2.id === id)));
|
|
16497
|
+
const stable = pack.sections.filter((section2) => !dynamic.has(section2.id));
|
|
16498
|
+
const window = typeof usage?.contextWindow === "number" && usage.contextWindow > 0 ? usage.contextWindow : null;
|
|
16499
|
+
const measuredTokens = typeof usage?.contextTokens === "number" && usage.contextTokens > 0 ? usage.contextTokens : null;
|
|
16500
|
+
let approximate = !sizes;
|
|
16501
|
+
if (snapshot2?.systemPromptTruncated || snapshot2?.contextUpdateTruncated || snapshot2?.toolsTruncated) approximate = true;
|
|
16502
|
+
const rows = [];
|
|
16503
|
+
for (const section2 of stable) {
|
|
16504
|
+
const chars = sizes?.system[section2.id] ?? section2.size;
|
|
16505
|
+
const variantChars = section2.id === "tools" ? Math.min(section2.sources.find((source2) => source2.kind === "variant")?.chars ?? 0, chars) : 0;
|
|
16506
|
+
const own = Math.max(0, chars - variantChars);
|
|
16507
|
+
if (own > 0) {
|
|
16508
|
+
rows.push({
|
|
16509
|
+
id: section2.id,
|
|
16510
|
+
title: section2.title,
|
|
16511
|
+
group: sectionGroup(section2, dynamic),
|
|
16512
|
+
tokens: tokensOf(own),
|
|
16513
|
+
chars: own,
|
|
16514
|
+
share: null,
|
|
16515
|
+
always: true,
|
|
16516
|
+
estimated: true,
|
|
16517
|
+
budget: section2.budget,
|
|
16518
|
+
...section2.cut ? { cut: true } : {},
|
|
16519
|
+
...section2.sources.length ? { sources: section2.sources.map((source2) => ({ ...source2 })) } : {}
|
|
16520
|
+
});
|
|
16521
|
+
}
|
|
16522
|
+
if (variantChars > 0) {
|
|
16523
|
+
rows.push({ id: "tool-guidance", title: "Tool guidance (c4)", group: "variant", tokens: tokensOf(variantChars), chars: variantChars, share: null, always: true, estimated: true });
|
|
16524
|
+
}
|
|
16525
|
+
}
|
|
16526
|
+
const framing = sizes?.systemFraming ?? 0;
|
|
16527
|
+
if (framing > 0) {
|
|
16528
|
+
rows.push({ id: "framing", title: "Prompt framing", group: "foundation", tokens: tokensOf(framing), chars: framing, share: null, always: true, estimated: true, note: "headings and the context-update guidance" });
|
|
16529
|
+
}
|
|
16530
|
+
const groupOfTool = /* @__PURE__ */ new Map();
|
|
16531
|
+
for (const group of pack.toolGroups) for (const name of group.tools) groupOfTool.set(name, group.group);
|
|
16532
|
+
for (const [group, harnessOwned] of [["foundation", true], ["application", false]]) {
|
|
16533
|
+
const owned = (snapshot2?.tools ?? []).filter((tool) => HARNESS_TOOL_GROUPS.has(groupOfTool.get(tool.name) ?? "") === harnessOwned);
|
|
16534
|
+
if (!owned.length) continue;
|
|
16535
|
+
const chars = owned.reduce((sum, tool) => sum + toolChars(tool), 0);
|
|
16536
|
+
const byGroup = /* @__PURE__ */ new Map();
|
|
16537
|
+
for (const tool of owned) {
|
|
16538
|
+
const name = groupOfTool.get(tool.name) ?? "Other tools";
|
|
16539
|
+
byGroup.set(name, (byGroup.get(name) ?? 0) + 1);
|
|
16540
|
+
}
|
|
16541
|
+
rows.push({
|
|
16542
|
+
id: harnessOwned ? "tools-harness" : "tools-application",
|
|
16543
|
+
title: `Tool schemas \xB7 ${owned.length} ${owned.length === 1 ? "tool" : "tools"}`,
|
|
16544
|
+
group,
|
|
16545
|
+
tokens: tokensOf(chars),
|
|
16546
|
+
chars,
|
|
16547
|
+
share: null,
|
|
16548
|
+
always: true,
|
|
16549
|
+
estimated: true,
|
|
16550
|
+
tools: [...byGroup].map(([name, count]) => ({ group: name, count }))
|
|
16551
|
+
});
|
|
16552
|
+
}
|
|
16553
|
+
for (const id of updatedIds) {
|
|
16554
|
+
const section2 = pack.sections.find((entry2) => entry2.id === id);
|
|
16555
|
+
if (!section2) continue;
|
|
16556
|
+
const chars = sizes?.update[section2.id] ?? section2.size;
|
|
16557
|
+
if (!chars) continue;
|
|
16558
|
+
rows.push({ id: section2.id, title: section2.title, group: "conversation", tokens: tokensOf(chars), chars, share: null, always: false, estimated: true });
|
|
16559
|
+
}
|
|
16560
|
+
const updateFraming = updatedIds.length ? sizes?.updateFraming ?? 0 : 0;
|
|
16561
|
+
if (updateFraming > 0) {
|
|
16562
|
+
rows.push({ id: "context-update", title: "Context update framing", group: "conversation", tokens: tokensOf(updateFraming), chars: updateFraming, share: null, always: false, estimated: true, note: "the message the sections arrived in" });
|
|
16563
|
+
}
|
|
16564
|
+
const prefix = rows.slice();
|
|
16565
|
+
let prefixTokens = prefix.reduce((sum, row) => sum + row.tokens, 0);
|
|
16566
|
+
let note = approximate ? "The pack was recorded without every per-section size, so the split is approximate." : "Rows are estimated from recorded characters, four per token, and reconciled to the measured request.";
|
|
16567
|
+
let messages = 0;
|
|
16568
|
+
let source = "estimate";
|
|
16569
|
+
if (measuredTokens !== null) {
|
|
16570
|
+
source = "measured";
|
|
16571
|
+
const remainder = measuredTokens - prefixTokens;
|
|
16572
|
+
if (remainder >= 0) messages = remainder;
|
|
16573
|
+
else {
|
|
16574
|
+
const scale = prefixTokens > 0 ? measuredTokens / prefixTokens : 0;
|
|
16575
|
+
for (const row of prefix) {
|
|
16576
|
+
row.tokens = Math.max(0, Math.floor(row.tokens * scale));
|
|
16577
|
+
row.note = "scaled to the measured total";
|
|
16578
|
+
}
|
|
16579
|
+
prefixTokens = prefix.reduce((sum, row) => sum + row.tokens, 0);
|
|
16580
|
+
messages = 0;
|
|
16581
|
+
note = "The estimated prefix exceeded the measured request, so every row was scaled down to it.";
|
|
16582
|
+
}
|
|
16583
|
+
rows.push({ id: "messages", title: "Messages and tool results", group: "conversation", tokens: messages, chars: null, share: null, always: false, estimated: false, note: "measured by subtraction" });
|
|
16584
|
+
} else {
|
|
16585
|
+
note = `${note} No request has been measured yet.`;
|
|
16586
|
+
}
|
|
16587
|
+
const reserve = snapshot2?.compaction?.enabled === true ? Math.max(0, Math.round(snapshot2.compaction.reserveTokens)) : null;
|
|
16588
|
+
if (reserve !== null) {
|
|
16589
|
+
rows.push({ id: "compaction-reserve", title: "Compaction reserve", group: "reserved", tokens: reserve, chars: null, share: null, always: true, estimated: true, note: "Pi, auto-compaction" });
|
|
16590
|
+
}
|
|
16591
|
+
for (const row of rows) row.share = shareOf(row.tokens, window);
|
|
16592
|
+
const used = measuredTokens ?? prefixTokens;
|
|
16593
|
+
const free = window === null ? null : Math.max(0, window - used - (reserve ?? 0));
|
|
16594
|
+
const totals2 = { foundation: 0, variant: 0, application: 0, conversation: 0, reserved: 0 };
|
|
16595
|
+
for (const row of rows) totals2[row.group] += row.tokens;
|
|
16596
|
+
const history = [];
|
|
16597
|
+
const compactions = [];
|
|
16598
|
+
for (const event of events2) {
|
|
16599
|
+
if (event.type === "usage.updated") {
|
|
16600
|
+
const payload2 = event.payload;
|
|
16601
|
+
const used2 = typeof payload2.contextTokens === "number" ? payload2.contextTokens : null;
|
|
16602
|
+
const request2 = typeof payload2.request?.index === "number" ? payload2.request.index : null;
|
|
16603
|
+
const index = request2 ?? (typeof payload2.request === "number" ? payload2.request : null);
|
|
16604
|
+
if (used2 === null || index === null) continue;
|
|
16605
|
+
history.push({ request: index, used: used2, share: shareOf(used2, window), at: event.timestamp });
|
|
16606
|
+
} else if (event.type === "compaction.ended") {
|
|
16607
|
+
const payload2 = event.payload;
|
|
16608
|
+
compactions.push({ at: event.timestamp, before: typeof payload2.tokensBefore === "number" ? payload2.tokensBefore : null, after: typeof payload2.tokensAfter === "number" ? payload2.tokensAfter : null });
|
|
16609
|
+
}
|
|
16610
|
+
}
|
|
16611
|
+
return {
|
|
16612
|
+
runId,
|
|
16613
|
+
model: usage?.model ?? null,
|
|
16614
|
+
provider: usage?.provider ?? null,
|
|
16615
|
+
window,
|
|
16616
|
+
used,
|
|
16617
|
+
share: shareOf(used, window),
|
|
16618
|
+
source,
|
|
16619
|
+
request: typeof usage?.request?.index === "number" ? usage.request.index : null,
|
|
16620
|
+
compaction: reserve === null ? null : { enabled: true, reserveTokens: reserve },
|
|
16621
|
+
free,
|
|
16622
|
+
rows: rows.sort((left, right) => GROUP_ORDER2.indexOf(left.group) - GROUP_ORDER2.indexOf(right.group)),
|
|
16623
|
+
history,
|
|
16624
|
+
compactions,
|
|
16625
|
+
onDemand: onDemandOf(env, pack),
|
|
16626
|
+
totals: totals2,
|
|
16627
|
+
recordedAt: pack.compiledAt ?? null,
|
|
16628
|
+
note
|
|
16629
|
+
};
|
|
16630
|
+
}
|
|
16631
|
+
function rowText(env, runId, rowId) {
|
|
16632
|
+
const pack = load2(env.root, runId);
|
|
16633
|
+
if (!pack) return null;
|
|
16634
|
+
if (rowId === "tools-harness" || rowId === "tools-application") {
|
|
16635
|
+
const events2 = readEvents(env.root, runId);
|
|
16636
|
+
const tools4 = lastEvent(events2, "context.snapshot")?.tools ?? [];
|
|
16637
|
+
if (!tools4.length) return null;
|
|
16638
|
+
const names2 = /* @__PURE__ */ new Map();
|
|
16639
|
+
for (const group of pack.toolGroups) for (const name of group.tools) names2.set(name, group.group);
|
|
16640
|
+
const harnessOwned = rowId === "tools-harness";
|
|
16641
|
+
const lines2 = tools4.filter((tool) => HARNESS_TOOL_GROUPS.has(names2.get(tool.name) ?? "") === harnessOwned).map((tool) => `${names2.get(tool.name) ?? "Other tools"}: ${tool.name}`);
|
|
16642
|
+
return { id: rowId, title: harnessOwned ? "Harness tool schemas" : "Application tool schemas", text: lines2.join("\n") };
|
|
16643
|
+
}
|
|
16644
|
+
const section2 = pack.sections.find((entry2) => entry2.id === rowId);
|
|
16645
|
+
if (!section2) return null;
|
|
16646
|
+
return { id: section2.id, title: section2.title, text: section2.body };
|
|
16647
|
+
}
|
|
16648
|
+
|
|
16204
16649
|
// src/sessions/workspaceBoundary.ts
|
|
16205
16650
|
var WORKSPACE_FILE_WRITE_TOOLS = /* @__PURE__ */ new Set(["edit", "write"]);
|
|
16206
16651
|
function inspectWorkspaceWrite(workspaceRoot, cwd, tool, input) {
|
|
@@ -16289,16 +16734,16 @@ function putIdle(path4, stream) {
|
|
|
16289
16734
|
entries2.add(entry2);
|
|
16290
16735
|
idle.set(path4, entries2);
|
|
16291
16736
|
}
|
|
16292
|
-
function request(connection, body2, what, timeoutMs) {
|
|
16737
|
+
function request(connection, body2, what, timeoutMs, signal) {
|
|
16293
16738
|
const reused = takeIdle(connection.socket);
|
|
16294
|
-
return attempt(connection, body2, what, timeoutMs, reused).catch((error) => {
|
|
16295
|
-
if (reused && error instanceof StaleConnection) return attempt(connection, body2, what, timeoutMs, void 0);
|
|
16739
|
+
return attempt(connection, body2, what, timeoutMs, reused, signal).catch((error) => {
|
|
16740
|
+
if (reused && error instanceof StaleConnection) return attempt(connection, body2, what, timeoutMs, void 0, signal);
|
|
16296
16741
|
throw error;
|
|
16297
16742
|
});
|
|
16298
16743
|
}
|
|
16299
16744
|
var StaleConnection = class extends Error {
|
|
16300
16745
|
};
|
|
16301
|
-
function attempt(connection, body2, what, timeoutMs, reused) {
|
|
16746
|
+
function attempt(connection, body2, what, timeoutMs, reused, signal) {
|
|
16302
16747
|
return new Promise((resolve19, reject2) => {
|
|
16303
16748
|
const stream = reused ?? createConnection(connection.socket);
|
|
16304
16749
|
let buffer = "";
|
|
@@ -16332,6 +16777,7 @@ function attempt(connection, body2, what, timeoutMs, reused) {
|
|
|
16332
16777
|
if (settled3) return;
|
|
16333
16778
|
settled3 = true;
|
|
16334
16779
|
clearTimeout(timer);
|
|
16780
|
+
signal?.removeEventListener("abort", onAbort);
|
|
16335
16781
|
stream.off("connect", send);
|
|
16336
16782
|
stream.off("data", onData);
|
|
16337
16783
|
stream.off("error", onError);
|
|
@@ -16348,6 +16794,15 @@ function attempt(connection, body2, what, timeoutMs, reused) {
|
|
|
16348
16794
|
stream.destroy();
|
|
16349
16795
|
finish(() => reject2(new SocketError("timeout", `The harness did not answer ${what}.`)));
|
|
16350
16796
|
}, timeoutMs);
|
|
16797
|
+
const onAbort = () => {
|
|
16798
|
+
stream.destroy();
|
|
16799
|
+
finish(() => reject2(new SocketError("aborted", `${what} was cancelled.`)));
|
|
16800
|
+
};
|
|
16801
|
+
if (signal?.aborted) {
|
|
16802
|
+
onAbort();
|
|
16803
|
+
return;
|
|
16804
|
+
}
|
|
16805
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
16351
16806
|
stream.on("data", onData);
|
|
16352
16807
|
stream.on("error", onError);
|
|
16353
16808
|
stream.on("close", onClose);
|
|
@@ -16355,8 +16810,8 @@ function attempt(connection, body2, what, timeoutMs, reused) {
|
|
|
16355
16810
|
else stream.on("connect", send);
|
|
16356
16811
|
});
|
|
16357
16812
|
}
|
|
16358
|
-
function socketCall(connection, call, params = {}, timeoutMs = 12e4, control) {
|
|
16359
|
-
return request(connection, { call, params, ...control ? { control } : {} }, call, timeoutMs);
|
|
16813
|
+
function socketCall(connection, call, params = {}, timeoutMs = 12e4, control, signal) {
|
|
16814
|
+
return request(connection, { call, params, ...control ? { control } : {} }, call, timeoutMs, signal);
|
|
16360
16815
|
}
|
|
16361
16816
|
|
|
16362
16817
|
// src/terminal/cli.ts
|
|
@@ -16631,7 +17086,10 @@ var TerminalController = class {
|
|
|
16631
17086
|
}
|
|
16632
17087
|
hooks;
|
|
16633
17088
|
run = null;
|
|
17089
|
+
lastRunId = null;
|
|
16634
17090
|
pending = /* @__PURE__ */ new Map();
|
|
17091
|
+
pendingRevision = 0;
|
|
17092
|
+
pendingWaiters = /* @__PURE__ */ new Set();
|
|
16635
17093
|
subagents = new SubagentMonitor();
|
|
16636
17094
|
subagentParentRunId = null;
|
|
16637
17095
|
ready = false;
|
|
@@ -16644,12 +17102,41 @@ var TerminalController = class {
|
|
|
16644
17102
|
nativeId;
|
|
16645
17103
|
seen = /* @__PURE__ */ new Map();
|
|
16646
17104
|
commands = [];
|
|
17105
|
+
pendingChanged() {
|
|
17106
|
+
this.pendingRevision += 1;
|
|
17107
|
+
for (const wake of this.pendingWaiters) wake();
|
|
17108
|
+
}
|
|
17109
|
+
setPending(key, value) {
|
|
17110
|
+
this.pending.set(key, value);
|
|
17111
|
+
this.pendingChanged();
|
|
17112
|
+
}
|
|
17113
|
+
deletePending(key) {
|
|
17114
|
+
if (this.pending.delete(key)) this.pendingChanged();
|
|
17115
|
+
}
|
|
17116
|
+
async waitPending(revision) {
|
|
17117
|
+
if (revision === this.pendingRevision && !this.disposed) {
|
|
17118
|
+
await new Promise((resolve19) => {
|
|
17119
|
+
const wake = () => {
|
|
17120
|
+
clearTimeout(timer);
|
|
17121
|
+
this.pendingWaiters.delete(wake);
|
|
17122
|
+
resolve19();
|
|
17123
|
+
};
|
|
17124
|
+
const timer = setTimeout(wake, 2e4);
|
|
17125
|
+
this.pendingWaiters.add(wake);
|
|
17126
|
+
});
|
|
17127
|
+
}
|
|
17128
|
+
return { revision: this.pendingRevision, requests: [...this.pending.values()] };
|
|
17129
|
+
}
|
|
16647
17130
|
get nativeSessionId() {
|
|
16648
17131
|
return this.nativeId;
|
|
16649
17132
|
}
|
|
16650
17133
|
get activeRun() {
|
|
16651
17134
|
return this.run && !this.run.finished ? this.run : null;
|
|
16652
17135
|
}
|
|
17136
|
+
/** The run this terminal is showing, or the last one it finished: `/context` reads it after a reply. */
|
|
17137
|
+
get lastRun() {
|
|
17138
|
+
return this.activeRun?.runId ?? this.lastRunId;
|
|
17139
|
+
}
|
|
16653
17140
|
state() {
|
|
16654
17141
|
return { ready: this.ready, dirty: this.dirty, active: !!this.activeRun || !!this.delivery };
|
|
16655
17142
|
}
|
|
@@ -16665,6 +17152,7 @@ var TerminalController = class {
|
|
|
16665
17152
|
if (delivery && text10 && delivery.text !== text10) throw new Error("The native prompt did not match the reserved delivery. Inspect the terminal before continuing.");
|
|
16666
17153
|
const run2 = this.hooks.begin({ reservedRunId: delivery?.runId ?? null, nativeTurnId, text: text10, ...launch });
|
|
16667
17154
|
this.run = run2;
|
|
17155
|
+
this.lastRunId = run2.runId;
|
|
16668
17156
|
this.subagentParentRunId = run2.runId;
|
|
16669
17157
|
this.subagents.begin(run2.runId);
|
|
16670
17158
|
run2.onInterrupt(() => void this.commands.push({ type: "interrupt" }));
|
|
@@ -16677,7 +17165,10 @@ var TerminalController = class {
|
|
|
16677
17165
|
this.run?.finish(outcome, message4 ? { code: "terminal_attention", message: message4 } : void 0, reason);
|
|
16678
17166
|
this.run = null;
|
|
16679
17167
|
this.seen.clear();
|
|
16680
|
-
this.pending.
|
|
17168
|
+
if (this.pending.size) {
|
|
17169
|
+
this.pending.clear();
|
|
17170
|
+
this.pendingChanged();
|
|
17171
|
+
}
|
|
16681
17172
|
}
|
|
16682
17173
|
/** Hands the native process an instruction and waits until it acknowledges the prompt. */
|
|
16683
17174
|
async send(runId, text10) {
|
|
@@ -16729,16 +17220,16 @@ var TerminalController = class {
|
|
|
16729
17220
|
if (this.disposed || !this.activeRun || !descendant && event.runId !== this.activeRun.runId) return;
|
|
16730
17221
|
if (event.type === "question.requested") {
|
|
16731
17222
|
const payload2 = event.payload;
|
|
16732
|
-
this.
|
|
17223
|
+
this.setPending(String(payload2.questionId), { ...payload2, type: "question", requestId: payload2.questionId, runId: event.runId });
|
|
16733
17224
|
} else if (event.type === "approval.requested") {
|
|
16734
17225
|
const payload2 = event.payload;
|
|
16735
17226
|
if (!payload2.automatic && (descendant || payload2.target === "workspace-write")) {
|
|
16736
|
-
this.
|
|
17227
|
+
this.setPending(String(payload2.approvalId), { ...payload2, type: "approval", requestId: payload2.approvalId, runId: event.runId });
|
|
16737
17228
|
}
|
|
16738
17229
|
} else if (event.type === "approval.resolved") {
|
|
16739
|
-
this.
|
|
17230
|
+
this.deletePending(String(event.payload.approvalId));
|
|
16740
17231
|
} else if (event.type === "question.answered") {
|
|
16741
|
-
this.
|
|
17232
|
+
this.deletePending(String(event.payload.questionId));
|
|
16742
17233
|
}
|
|
16743
17234
|
}
|
|
16744
17235
|
/** A child event that belongs to the active terminal parent run. */
|
|
@@ -16773,6 +17264,7 @@ var TerminalController = class {
|
|
|
16773
17264
|
return {};
|
|
16774
17265
|
}
|
|
16775
17266
|
if (call === "terminal.pending") return { requests: [...this.pending.values()] };
|
|
17267
|
+
if (call === "terminal.pending.wait") return this.waitPending(data.revision);
|
|
16776
17268
|
if (call === "terminal.interrupt") return this.activeRun && this.hooks.interrupt ? this.hooks.interrupt(this.activeRun.runId) : {};
|
|
16777
17269
|
if (call === "terminal.policy") {
|
|
16778
17270
|
const run3 = this.activeRun;
|
|
@@ -16852,7 +17344,7 @@ var TerminalController = class {
|
|
|
16852
17344
|
rememberable: policy.rememberable === true,
|
|
16853
17345
|
standing: policy.standing
|
|
16854
17346
|
});
|
|
16855
|
-
this.
|
|
17347
|
+
this.setPending(key, {
|
|
16856
17348
|
type: "approval",
|
|
16857
17349
|
requestId: key,
|
|
16858
17350
|
runId: run2.runId,
|
|
@@ -16866,7 +17358,7 @@ var TerminalController = class {
|
|
|
16866
17358
|
try {
|
|
16867
17359
|
return { decision: await response };
|
|
16868
17360
|
} finally {
|
|
16869
|
-
this.
|
|
17361
|
+
this.deletePending(key);
|
|
16870
17362
|
}
|
|
16871
17363
|
}
|
|
16872
17364
|
async accept(event, data) {
|
|
@@ -16935,9 +17427,9 @@ var TerminalController = class {
|
|
|
16935
17427
|
const summary4 = typeof data.summary === "string" && data.summary.trim() ? data.summary.trim() : void 0;
|
|
16936
17428
|
const sketchMode = data.uiSketch === void 0 ? {} : { uiSketch: data.uiSketch };
|
|
16937
17429
|
const response2 = run2.requestAnswer({ requestId: key, ...summary4 ? { summary: summary4 } : {}, ...sketchMode, question: String(data.question ?? ""), options: data.options ?? [], multiSelect: !!data.multiSelect, allowText: true });
|
|
16938
|
-
this.
|
|
17430
|
+
this.setPending(key, { type: "question", requestId: key, ...summary4 ? { summary: summary4 } : {}, ...sketchMode, question: String(data.question ?? ""), options: data.options ?? [], multiSelect: !!data.multiSelect });
|
|
16939
17431
|
this.seen.set(key, response2);
|
|
16940
|
-
return response2.finally(() => this.
|
|
17432
|
+
return response2.finally(() => this.deletePending(key));
|
|
16941
17433
|
}
|
|
16942
17434
|
const response = run2.requestApproval({
|
|
16943
17435
|
requestId: key,
|
|
@@ -16946,12 +17438,12 @@ var TerminalController = class {
|
|
|
16946
17438
|
operation: { tool: String(data.tool ?? data.target), args: data.args ?? {} },
|
|
16947
17439
|
rememberable: false
|
|
16948
17440
|
});
|
|
16949
|
-
this.
|
|
17441
|
+
this.setPending(key, { type: "approval", requestId: key, target: String(data.target ?? "Action"), action: String(data.action ?? "{}") });
|
|
16950
17442
|
this.seen.set(key, response);
|
|
16951
17443
|
try {
|
|
16952
17444
|
return { decision: await response };
|
|
16953
17445
|
} finally {
|
|
16954
|
-
this.
|
|
17446
|
+
this.deletePending(key);
|
|
16955
17447
|
}
|
|
16956
17448
|
}
|
|
16957
17449
|
if (event === "usage") run2.emit("usage.updated", data);
|
|
@@ -16971,6 +17463,7 @@ var TerminalController = class {
|
|
|
16971
17463
|
dispose() {
|
|
16972
17464
|
if (this.disposed) return;
|
|
16973
17465
|
this.disposed = true;
|
|
17466
|
+
this.pendingChanged();
|
|
16974
17467
|
this.ready = false;
|
|
16975
17468
|
this.delivery?.reject(new Error("The terminal stopped before prompt acknowledgement."));
|
|
16976
17469
|
this.delivery = null;
|
|
@@ -17013,32 +17506,32 @@ exit /b %ERRORLEVEL%\r
|
|
|
17013
17506
|
|
|
17014
17507
|
// src/terminal/socket.ts
|
|
17015
17508
|
import { randomBytes } from "node:crypto";
|
|
17016
|
-
import { chmodSync as chmodSync10, mkdirSync as mkdirSync21, readdirSync as
|
|
17509
|
+
import { chmodSync as chmodSync10, mkdirSync as mkdirSync21, readdirSync as readdirSync27, rmSync as rmSync22, statSync as statSync18 } from "node:fs";
|
|
17017
17510
|
import { createServer as createServer2 } from "node:net";
|
|
17018
17511
|
import { tmpdir as tmpdir7 } from "node:os";
|
|
17019
|
-
import { dirname as dirname18, join as
|
|
17512
|
+
import { dirname as dirname18, join as join56 } from "node:path";
|
|
17020
17513
|
init_errors();
|
|
17021
17514
|
init_fs();
|
|
17022
17515
|
var MAX_REQUEST_BYTES = 1024 * 1024;
|
|
17023
17516
|
var MAX_SOCKET_PATH = 100;
|
|
17024
17517
|
function socketPath(stateDir) {
|
|
17025
17518
|
if (process.platform === "win32") return `\\\\.\\pipe\\xingular-harness-${randomBytes(12).toString("hex")}`;
|
|
17026
|
-
const path4 =
|
|
17519
|
+
const path4 = join56(stateDir, "run", `harness-${process.pid}-${randomBytes(8).toString("hex")}.sock`);
|
|
17027
17520
|
if (Buffer.byteLength(path4) <= MAX_SOCKET_PATH) return path4;
|
|
17028
|
-
return
|
|
17521
|
+
return join56(tmpdir7(), `xh-${process.pid}-${randomBytes(8).toString("hex")}.sock`);
|
|
17029
17522
|
}
|
|
17030
17523
|
var OWN_SOCKET = /^harness-(\d+)-[0-9a-f]+\.sock$/;
|
|
17031
17524
|
function pruneDeadSockets(folder2) {
|
|
17032
17525
|
let names2;
|
|
17033
17526
|
try {
|
|
17034
|
-
names2 =
|
|
17527
|
+
names2 = readdirSync27(folder2);
|
|
17035
17528
|
} catch {
|
|
17036
17529
|
return;
|
|
17037
17530
|
}
|
|
17038
17531
|
for (const name of names2) {
|
|
17039
17532
|
const pid = Number(OWN_SOCKET.exec(name)?.[1]);
|
|
17040
17533
|
if (!pid || pid === process.pid || isRunning(pid)) continue;
|
|
17041
|
-
rmSync22(
|
|
17534
|
+
rmSync22(join56(folder2, name), { force: true });
|
|
17042
17535
|
}
|
|
17043
17536
|
}
|
|
17044
17537
|
function isRunning(pid) {
|
|
@@ -17050,8 +17543,8 @@ function isRunning(pid) {
|
|
|
17050
17543
|
}
|
|
17051
17544
|
}
|
|
17052
17545
|
function alternateSocketPath(path4) {
|
|
17053
|
-
const candidate =
|
|
17054
|
-
return Buffer.byteLength(candidate) <= MAX_SOCKET_PATH ? candidate :
|
|
17546
|
+
const candidate = join56(dirname18(path4), `harness-${process.pid}-${randomBytes(8).toString("hex")}.sock`);
|
|
17547
|
+
return Buffer.byteLength(candidate) <= MAX_SOCKET_PATH ? candidate : join56(tmpdir7(), `xh-${process.pid}-${randomBytes(8).toString("hex")}.sock`);
|
|
17055
17548
|
}
|
|
17056
17549
|
var isPipePath = (path4) => path4.startsWith("\\\\.\\pipe\\");
|
|
17057
17550
|
function refusedBind(path4, error) {
|
|
@@ -17066,7 +17559,7 @@ function refusedBind(path4, error) {
|
|
|
17066
17559
|
}
|
|
17067
17560
|
let folder2;
|
|
17068
17561
|
try {
|
|
17069
|
-
const stat =
|
|
17562
|
+
const stat = statSync18(dirname18(path4));
|
|
17070
17563
|
folder2 = `${dirname18(path4)} is owned by uid ${stat.uid} with mode ${(stat.mode & 511).toString(8)}`;
|
|
17071
17564
|
} catch {
|
|
17072
17565
|
folder2 = `${dirname18(path4)} could not be read`;
|
|
@@ -17263,12 +17756,12 @@ var SessionSocket = class {
|
|
|
17263
17756
|
};
|
|
17264
17757
|
|
|
17265
17758
|
// src/terminal/logs.ts
|
|
17266
|
-
import { closeSync as closeSync5, openSync as openSync5, readSync, statSync as
|
|
17267
|
-
import { join as
|
|
17759
|
+
import { closeSync as closeSync5, openSync as openSync5, readSync, statSync as statSync19 } from "node:fs";
|
|
17760
|
+
import { join as join57 } from "node:path";
|
|
17268
17761
|
var LOG_READ_CHUNK_BYTES = 32 * 1024;
|
|
17269
17762
|
function harnessLogInfo(stateDir) {
|
|
17270
17763
|
try {
|
|
17271
|
-
const stat =
|
|
17764
|
+
const stat = statSync19(join57(stateDir, "harness.log"));
|
|
17272
17765
|
if (!stat.isFile()) throw new Error("The Harness diagnostics path is not a regular file.");
|
|
17273
17766
|
return { size: stat.size };
|
|
17274
17767
|
} catch (error) {
|
|
@@ -17280,8 +17773,8 @@ function readHarnessLogChunk(stateDir, snapshotSize, offset) {
|
|
|
17280
17773
|
if (!Number.isSafeInteger(snapshotSize) || snapshotSize < 0 || !Number.isSafeInteger(offset) || offset < 0 || offset >= snapshotSize) {
|
|
17281
17774
|
throw new Error("The Harness diagnostics snapshot range is invalid.");
|
|
17282
17775
|
}
|
|
17283
|
-
const path4 =
|
|
17284
|
-
const current2 =
|
|
17776
|
+
const path4 = join57(stateDir, "harness.log");
|
|
17777
|
+
const current2 = statSync19(path4);
|
|
17285
17778
|
if (!current2.isFile() || current2.size < snapshotSize) throw new Error("The Harness diagnostics file changed while it was being read.");
|
|
17286
17779
|
const length = Math.min(LOG_READ_CHUNK_BYTES, snapshotSize - offset);
|
|
17287
17780
|
const buffer = Buffer.allocUnsafe(length);
|
|
@@ -17325,7 +17818,7 @@ function readTerminalTrajectory(root, sessionId, nativeSessionId, runId, afterSe
|
|
|
17325
17818
|
}
|
|
17326
17819
|
|
|
17327
17820
|
// src/terminal/browserControl.ts
|
|
17328
|
-
import { constants as constants5, closeSync as closeSync6, fstatSync, lstatSync as lstatSync12, openSync as openSync6, readFileSync as
|
|
17821
|
+
import { constants as constants5, closeSync as closeSync6, fstatSync, lstatSync as lstatSync12, openSync as openSync6, readFileSync as readFileSync28, readdirSync as readdirSync28, realpathSync as realpathSync5 } from "node:fs";
|
|
17329
17822
|
|
|
17330
17823
|
// src/plugins/surfaces.ts
|
|
17331
17824
|
function describePlugin(plugin) {
|
|
@@ -17336,7 +17829,7 @@ function describePlugin(plugin) {
|
|
|
17336
17829
|
// src/terminal/browserControl.ts
|
|
17337
17830
|
init_errors();
|
|
17338
17831
|
import * as path3 from "node:path";
|
|
17339
|
-
import { basename as basename11, dirname as dirname19, join as
|
|
17832
|
+
import { basename as basename11, dirname as dirname19, join as join58, relative as relative8, resolve as resolve9 } from "node:path";
|
|
17340
17833
|
var MAX_CONTENT = 256 * 1024;
|
|
17341
17834
|
function isWithinBoundary(boundary, file2, pathApi = path3) {
|
|
17342
17835
|
const within2 = pathApi.relative(boundary, file2);
|
|
@@ -17347,7 +17840,7 @@ function readText2(path4) {
|
|
|
17347
17840
|
try {
|
|
17348
17841
|
const stat = fstatSync(fd);
|
|
17349
17842
|
if (!stat.isFile() || stat.size > MAX_CONTENT) throw invalid("Preview requires a regular text file smaller than 256 KiB.");
|
|
17350
|
-
return
|
|
17843
|
+
return readFileSync28(fd, "utf8");
|
|
17351
17844
|
} finally {
|
|
17352
17845
|
closeSync6(fd);
|
|
17353
17846
|
}
|
|
@@ -17446,7 +17939,7 @@ var BrowserControl = class {
|
|
|
17446
17939
|
});
|
|
17447
17940
|
if (/^skills\/[^/]+\/SKILL\.md$/.test(path4) && current2 !== void 0) {
|
|
17448
17941
|
const name = path4.split("/")[1];
|
|
17449
|
-
const fullPath =
|
|
17942
|
+
const fullPath = join58(pinned.dir, path4);
|
|
17450
17943
|
if (!items.some((item) => item.section === "skills" && item.path === fullPath)) add({
|
|
17451
17944
|
id: `variant-skill:${path4}`,
|
|
17452
17945
|
section: "skills",
|
|
@@ -17497,7 +17990,7 @@ var BrowserControl = class {
|
|
|
17497
17990
|
if (!item.path) throw invalid("This resource has no file.");
|
|
17498
17991
|
const plugin = snapshot2.plugins.find((plugin2) => plugin2.id === item.pluginId);
|
|
17499
17992
|
const registryItem = item.componentId ? list5(root).find((entry2) => entry2.id === item.componentId) : void 0;
|
|
17500
|
-
const boundary = realpathSync5(registryItem && !registryItem.builtin ?
|
|
17993
|
+
const boundary = realpathSync5(registryItem && !registryItem.builtin ? join58(root, "registry") : plugin?.path ?? dirname19(item.path));
|
|
17501
17994
|
const file2 = realpathSync5(item.path);
|
|
17502
17995
|
if (!isWithinBoundary(boundary, file2)) throw invalid("Resource is outside its owner folder.");
|
|
17503
17996
|
return { content: readText2(file2) };
|
|
@@ -17511,9 +18004,9 @@ var BrowserControl = class {
|
|
|
17511
18004
|
let directories = 0;
|
|
17512
18005
|
const visit = (directory, depth2 = 0) => {
|
|
17513
18006
|
if (++directories > 100 || depth2 > 16) throw invalid("Skill import exceeds its directory limit.");
|
|
17514
|
-
for (const name of
|
|
18007
|
+
for (const name of readdirSync28(directory)) {
|
|
17515
18008
|
if (name.startsWith(".")) continue;
|
|
17516
|
-
const path4 =
|
|
18009
|
+
const path4 = join58(directory, name);
|
|
17517
18010
|
const stat = lstatSync12(path4);
|
|
17518
18011
|
if (stat.isSymbolicLink()) throw invalid("Skill imports cannot contain symbolic links.");
|
|
17519
18012
|
if (stat.isDirectory()) {
|
|
@@ -17523,7 +18016,7 @@ var BrowserControl = class {
|
|
|
17523
18016
|
if (!stat.isFile() || files3.length >= 100 || stat.size > 10 * 1024 * 1024) throw invalid("Skill import exceeds its file limit.");
|
|
17524
18017
|
bytes += stat.size;
|
|
17525
18018
|
if (bytes > 10 * 1024 * 1024) throw invalid("Skill import exceeds 10 MiB.");
|
|
17526
|
-
files3.push({ path: relative8(folder2, path4), content:
|
|
18019
|
+
files3.push({ path: relative8(folder2, path4), content: readFileSync28(path4).toString("base64"), encoding: "base64" });
|
|
17527
18020
|
}
|
|
17528
18021
|
};
|
|
17529
18022
|
if (lstatSync12(folder2).isSymbolicLink()) throw invalid("Choose a regular skill folder.");
|
|
@@ -17568,12 +18061,12 @@ function resourceIdentity(loading) {
|
|
|
17568
18061
|
}
|
|
17569
18062
|
function defaultAssets() {
|
|
17570
18063
|
const here = dirname20(fileURLToPath2(import.meta.url));
|
|
17571
|
-
const dist = [here,
|
|
18064
|
+
const dist = [here, join59(here, "..", ".."), join59(here, "..", "..", "dist"), join59(here, "..", "dist")].find((folder2) => existsSync26(join59(folder2, "terminal-pi.js"))) ?? here;
|
|
17572
18065
|
return {
|
|
17573
18066
|
node: process.execPath,
|
|
17574
|
-
cli:
|
|
17575
|
-
piExtension:
|
|
17576
|
-
openTui:
|
|
18067
|
+
cli: join59(dist, "cli.js"),
|
|
18068
|
+
piExtension: join59(dist, "terminal-pi.js"),
|
|
18069
|
+
openTui: join59(dist, "terminal-opentui.js")
|
|
17577
18070
|
};
|
|
17578
18071
|
}
|
|
17579
18072
|
var READ_ONLY_TOOLS2 = /* @__PURE__ */ new Set(["read", "grep", "find", "ls"]);
|
|
@@ -17690,10 +18183,10 @@ var Terminals = class {
|
|
|
17690
18183
|
}
|
|
17691
18184
|
/** The commands a terminal session finds on PATH. Rewritten only when they change. */
|
|
17692
18185
|
ensureCommands() {
|
|
17693
|
-
const bin =
|
|
18186
|
+
const bin = join59(this.options.stateDir, "run", "bin");
|
|
17694
18187
|
mkdirSync22(bin, { recursive: true });
|
|
17695
18188
|
for (const name of ["agentx-wiki", "agentx-mcp", "agentx-wiki.cmd", "agentx-mcp.cmd"]) {
|
|
17696
|
-
const path4 =
|
|
18189
|
+
const path4 = join59(bin, name);
|
|
17697
18190
|
try {
|
|
17698
18191
|
if (lstatSync13(path4).isFile()) unlinkSync5(path4);
|
|
17699
18192
|
} catch {
|
|
@@ -17701,10 +18194,10 @@ var Terminals = class {
|
|
|
17701
18194
|
}
|
|
17702
18195
|
for (const [name, mode2] of [[WIKI_COMMAND, "wiki"], [APPS_COMMAND, "mcp"]]) {
|
|
17703
18196
|
for (const file2 of terminalCommandFiles(process.platform, this.assets.node, this.assets.cli, name, mode2)) {
|
|
17704
|
-
const path4 =
|
|
18197
|
+
const path4 = join59(bin, file2.name);
|
|
17705
18198
|
let current2 = null;
|
|
17706
18199
|
try {
|
|
17707
|
-
current2 =
|
|
18200
|
+
current2 = readFileSync29(path4, "utf8");
|
|
17708
18201
|
} catch {
|
|
17709
18202
|
current2 = null;
|
|
17710
18203
|
}
|
|
@@ -18034,6 +18527,13 @@ var Terminals = class {
|
|
|
18034
18527
|
throw new HarnessError("unknown_method", `Unknown call ${call}.`);
|
|
18035
18528
|
}
|
|
18036
18529
|
}
|
|
18530
|
+
/** `/context`: what the session's latest request was made of, and one row's text on request. */
|
|
18531
|
+
contextCall(live, params) {
|
|
18532
|
+
const runId = live.controller.lastRun;
|
|
18533
|
+
if (!runId) return { attribution: null, text: null };
|
|
18534
|
+
const text10 = typeof params.section === "string" && params.section ? rowText(this.options.env, runId, params.section) : null;
|
|
18535
|
+
return { attribution: attribution(this.options.env, runId), text: text10 };
|
|
18536
|
+
}
|
|
18037
18537
|
/** `/usage:analysis` and `/usage:limit`: usage for this session's own account, project or session. */
|
|
18038
18538
|
async usageCall(live, call, params) {
|
|
18039
18539
|
const usage = this.options.usage;
|
|
@@ -18187,7 +18687,7 @@ var Terminals = class {
|
|
|
18187
18687
|
return live;
|
|
18188
18688
|
}
|
|
18189
18689
|
historyDir(input) {
|
|
18190
|
-
return
|
|
18690
|
+
return join59(input.sessionFolder, "pi");
|
|
18191
18691
|
}
|
|
18192
18692
|
runRecord(live, runId, text10) {
|
|
18193
18693
|
const { input } = live;
|
|
@@ -18685,6 +19185,7 @@ ${formatBashCommandForApproval(command)}`,
|
|
|
18685
19185
|
return { globalTools: policy.globalTools.pi ?? [] };
|
|
18686
19186
|
}
|
|
18687
19187
|
if (call.startsWith("terminal.usage.")) return this.usageCall(live, call, params);
|
|
19188
|
+
if (call === "terminal.context") return this.contextCall(live, params);
|
|
18688
19189
|
if (call !== "terminal.resources") return live.controller.control(call, params);
|
|
18689
19190
|
const current2 = await this.options.plugins?.loading({ cwd: input.cwd, agentDir: configDir(accounts.dir, preparedAccount), install: false, caller: { projectId: input.projectId ?? null } }) ?? null;
|
|
18690
19191
|
const currentVariant = variant ? materialise(root, { dir: variant.dir, scope: variant.scope }, { trust: this.options.trust ?? null }) : null;
|
|
@@ -18797,11 +19298,11 @@ ${formatBashCommandForApproval(command)}`,
|
|
|
18797
19298
|
var pass = (evidence) => ({ status: "pass", evidence });
|
|
18798
19299
|
var fail = (evidence, remedy) => ({ status: "fail", evidence, remedy });
|
|
18799
19300
|
function resolvedExecutable(name) {
|
|
18800
|
-
const paths2 = isAbsolute8(name) ? [name] : (process.env.PATH ?? "").split(delimiter2).filter(Boolean).map((dir2) =>
|
|
19301
|
+
const paths2 = isAbsolute8(name) ? [name] : (process.env.PATH ?? "").split(delimiter2).filter(Boolean).map((dir2) => join60(dir2, name));
|
|
18801
19302
|
for (const path4 of paths2) {
|
|
18802
19303
|
try {
|
|
18803
19304
|
accessSync5(path4, constants6.X_OK);
|
|
18804
|
-
if (
|
|
19305
|
+
if (statSync20(path4).isFile()) return path4;
|
|
18805
19306
|
} catch {
|
|
18806
19307
|
}
|
|
18807
19308
|
}
|
|
@@ -18821,7 +19322,7 @@ async function builtinChecks(harness, context, secrets, assets = defaultAssets()
|
|
|
18821
19322
|
const saved = harness.accounts.overview().accounts.find((item) => item.id === selected.id);
|
|
18822
19323
|
const inspected = await harness.accounts.inspect(selected.id, signal);
|
|
18823
19324
|
if (!inspected.credentials) return fail("The pinned account has no saved provider credentials.", "Sign in or add a key in /accounts.");
|
|
18824
|
-
return { status: saved.state.health === "ok" || saved.state.health === "unknown" ? "pass" : "warning", evidence: `Credentials are configured. Saved health: ${saved.state.health}; checked ${saved.state.lastCheckedAt ?? "never"}. ${saved.state.limits.map((
|
|
19325
|
+
return { status: saved.state.health === "ok" || saved.state.health === "unknown" ? "pass" : "warning", evidence: `Credentials are configured. Saved health: ${saved.state.health}; checked ${saved.state.lastCheckedAt ?? "never"}. ${saved.state.limits.map((limit2) => `${limit2.label || limit2.id}: ${limit2.usedPercent}% used; resets ${limit2.resetsAt ?? "unknown"}`).join("; ")} ${saved.state.lastError ? `Saved issue: ${saved.state.lastError.category}.` : ""} This does not verify authentication with the provider.`, remedy: saved.state.health === "ok" ? void 0 : "Use the model live probe to verify current provider access." };
|
|
18825
19326
|
}),
|
|
18826
19327
|
check2("accounts.inventory", "account", "Other saved accounts", async () => {
|
|
18827
19328
|
const others = harness.accounts.overview().accounts.filter((item) => item.id !== context.accountId);
|
|
@@ -18960,7 +19461,7 @@ async function builtinChecks(harness, context, secrets, assets = defaultAssets()
|
|
|
18960
19461
|
if (item.path) {
|
|
18961
19462
|
try {
|
|
18962
19463
|
accessSync5(item.path, constants6.R_OK);
|
|
18963
|
-
if (item.kind === "skill")
|
|
19464
|
+
if (item.kind === "skill") readFileSync30(item.path, "utf8");
|
|
18964
19465
|
} catch {
|
|
18965
19466
|
problems.push(`${item.name}: resource cannot be read`);
|
|
18966
19467
|
}
|
|
@@ -19116,7 +19617,7 @@ async function diagnosticProbe(harness, context, inputSignal, action) {
|
|
|
19116
19617
|
|
|
19117
19618
|
// src/plugins/hooks.ts
|
|
19118
19619
|
import { chmodSync as chmodSync12 } from "node:fs";
|
|
19119
|
-
import { join as
|
|
19620
|
+
import { join as join61 } from "node:path";
|
|
19120
19621
|
import { pathToFileURL as pathToFileURL2 } from "node:url";
|
|
19121
19622
|
init_fs();
|
|
19122
19623
|
var HOOK_EVENTS = ["wiki.page.saved", "history.run.ended"];
|
|
@@ -19131,7 +19632,7 @@ function entryEvent(change) {
|
|
|
19131
19632
|
var Hooks = class {
|
|
19132
19633
|
constructor(options2) {
|
|
19133
19634
|
this.options = options2;
|
|
19134
|
-
this.statusPath =
|
|
19635
|
+
this.statusPath = join61(options2.stateDir, "plugin-hooks.json");
|
|
19135
19636
|
this.stop = onChange((change) => {
|
|
19136
19637
|
if (change.wiki === this.wiki) this.emit(entryEvent(change));
|
|
19137
19638
|
});
|
|
@@ -19247,7 +19748,7 @@ var Hooks = class {
|
|
|
19247
19748
|
init_errors();
|
|
19248
19749
|
init_fs();
|
|
19249
19750
|
import { chmodSync as chmodSync13 } from "node:fs";
|
|
19250
|
-
import { join as
|
|
19751
|
+
import { join as join62 } from "node:path";
|
|
19251
19752
|
var APPROVAL_KEYS = ["chat", "pi"];
|
|
19252
19753
|
function decide(policy, key, sessionId, target) {
|
|
19253
19754
|
if (policy.auto[key]) return "always";
|
|
@@ -19262,7 +19763,7 @@ var approvalKey = (run2) => run2.mode === "chat" ? "chat" : run2.harness;
|
|
|
19262
19763
|
var Approvals = class {
|
|
19263
19764
|
constructor(stateDir, bus) {
|
|
19264
19765
|
this.bus = bus;
|
|
19265
|
-
this.path =
|
|
19766
|
+
this.path = join62(stateDir, "approvals.json");
|
|
19266
19767
|
}
|
|
19267
19768
|
bus;
|
|
19268
19769
|
path;
|
|
@@ -19664,7 +20165,7 @@ var RunRegistry = class {
|
|
|
19664
20165
|
// src/sessions/sessions.ts
|
|
19665
20166
|
import { randomUUID as randomUUID17 } from "node:crypto";
|
|
19666
20167
|
import { existsSync as existsSync28, mkdirSync as mkdirSync23 } from "node:fs";
|
|
19667
|
-
import { isAbsolute as isAbsolute9, join as
|
|
20168
|
+
import { isAbsolute as isAbsolute9, join as join63 } from "node:path";
|
|
19668
20169
|
init_errors();
|
|
19669
20170
|
init_fs();
|
|
19670
20171
|
|
|
@@ -19758,12 +20259,12 @@ function runLineageJoin(root, runId) {
|
|
|
19758
20259
|
}
|
|
19759
20260
|
|
|
19760
20261
|
// src/sessions/sessionState.ts
|
|
19761
|
-
import { readFileSync as
|
|
20262
|
+
import { readFileSync as readFileSync31 } from "node:fs";
|
|
19762
20263
|
function latestSessionName(historyFile) {
|
|
19763
20264
|
if (!historyFile) return null;
|
|
19764
20265
|
let text10;
|
|
19765
20266
|
try {
|
|
19766
|
-
text10 =
|
|
20267
|
+
text10 = readFileSync31(historyFile, "utf8");
|
|
19767
20268
|
} catch {
|
|
19768
20269
|
return null;
|
|
19769
20270
|
}
|
|
@@ -19858,7 +20359,7 @@ init_errors();
|
|
|
19858
20359
|
import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
|
|
19859
20360
|
import { spawn as spawn4 } from "node:child_process";
|
|
19860
20361
|
import { createHash as createHash14 } from "node:crypto";
|
|
19861
|
-
import { constants as fsConstants, realpathSync as realpathSync6, statSync as
|
|
20362
|
+
import { constants as fsConstants, realpathSync as realpathSync6, statSync as statSync21 } from "node:fs";
|
|
19862
20363
|
import { access, readFile } from "node:fs/promises";
|
|
19863
20364
|
import { dirname as dirname21, resolve as resolve10 } from "node:path";
|
|
19864
20365
|
var writeAuthorization = new AsyncLocalStorage2();
|
|
@@ -19931,7 +20432,7 @@ function nearestExistingDirectory(path4) {
|
|
|
19931
20432
|
while (true) {
|
|
19932
20433
|
try {
|
|
19933
20434
|
const canonical2 = realpathSync6(current2);
|
|
19934
|
-
if (!
|
|
20435
|
+
if (!statSync21(canonical2).isDirectory()) throw new Error(`Write scope is not a directory: ${canonical2}`);
|
|
19935
20436
|
return canonical2;
|
|
19936
20437
|
} catch (error) {
|
|
19937
20438
|
if (error.code !== "ENOENT") throw error;
|
|
@@ -20295,6 +20796,17 @@ function contextToolSpecs(session) {
|
|
|
20295
20796
|
});
|
|
20296
20797
|
return { tools: tools4.map((entry2) => entry2.spec), truncated: source.length > MAX_TOOL_SPECS || tools4.some((entry2) => entry2.truncated) };
|
|
20297
20798
|
}
|
|
20799
|
+
function compactionSettings(session) {
|
|
20800
|
+
const manager2 = session.settingsManager;
|
|
20801
|
+
if (!manager2?.getCompactionSettings) return null;
|
|
20802
|
+
try {
|
|
20803
|
+
const model = session.model?.id && session.model.provider ? { provider: session.model.provider, id: session.model.id } : void 0;
|
|
20804
|
+
const settings = manager2.getCompactionSettings(model);
|
|
20805
|
+
return { enabled: settings.enabled === true, reserveTokens: Math.max(0, Math.round(settings.reserveTokens || 0)) };
|
|
20806
|
+
} catch {
|
|
20807
|
+
return null;
|
|
20808
|
+
}
|
|
20809
|
+
}
|
|
20298
20810
|
var numberField = (event, key, fallback = 0) => typeof event[key] === "number" && Number.isFinite(event[key]) ? event[key] : fallback;
|
|
20299
20811
|
var stringField = (event, key, fallback = "") => typeof event[key] === "string" ? event[key] : fallback;
|
|
20300
20812
|
var lastLine = (text10) => {
|
|
@@ -20344,10 +20856,12 @@ async function runTurn(run2, session, params) {
|
|
|
20344
20856
|
const systemPrompt = limitedText(session.systemPrompt ?? params.system, MAX_SYSTEM_PROMPT_CHARS);
|
|
20345
20857
|
const contextUpdate = limitedText(params.update?.content ?? "", MAX_SYSTEM_PROMPT_CHARS);
|
|
20346
20858
|
const toolSpecs = contextToolSpecs(session);
|
|
20859
|
+
const compaction = compactionSettings(session);
|
|
20347
20860
|
run2.emit("context.snapshot", {
|
|
20348
20861
|
systemPrompt: systemPrompt.text,
|
|
20349
20862
|
...contextUpdate.text ? { contextUpdate: contextUpdate.text } : {},
|
|
20350
20863
|
tools: toolSpecs.tools,
|
|
20864
|
+
...compaction ? { compaction } : {},
|
|
20351
20865
|
...systemPrompt.truncated ? { systemPromptTruncated: true } : {},
|
|
20352
20866
|
...contextUpdate.truncated ? { contextUpdateTruncated: true } : {},
|
|
20353
20867
|
...toolSpecs.truncated ? { toolsTruncated: true } : {}
|
|
@@ -20532,14 +21046,14 @@ async function runTurn(run2, session, params) {
|
|
|
20532
21046
|
break;
|
|
20533
21047
|
}
|
|
20534
21048
|
case "compaction_end": {
|
|
20535
|
-
const
|
|
20536
|
-
const summary4 = evidenceText(
|
|
21049
|
+
const compaction2 = event;
|
|
21050
|
+
const summary4 = evidenceText(compaction2.result);
|
|
20537
21051
|
const boundedSummary = summary4 ? limitedText(summary4) : null;
|
|
20538
21052
|
run2.emit("compaction.ended", {
|
|
20539
|
-
reason: stringField(
|
|
20540
|
-
aborted:
|
|
20541
|
-
...typeof
|
|
20542
|
-
...stringField(
|
|
21053
|
+
reason: stringField(compaction2, "reason", "context limit"),
|
|
21054
|
+
aborted: compaction2.aborted === true,
|
|
21055
|
+
...typeof compaction2.willRetry === "boolean" ? { willRetry: compaction2.willRetry } : {},
|
|
21056
|
+
...stringField(compaction2, "errorMessage") ? { error: stringField(compaction2, "errorMessage").slice(0, 1e3) } : {},
|
|
20543
21057
|
...boundedSummary ? { summary: boundedSummary.text, ...boundedSummary.truncated ? { summaryTruncated: true } : {} } : {}
|
|
20544
21058
|
});
|
|
20545
21059
|
if (slice) slice.compactions += 1;
|
|
@@ -21290,7 +21804,7 @@ Attached saved file references:`);
|
|
|
21290
21804
|
...input.effort ? { effort: input.effort } : {}
|
|
21291
21805
|
});
|
|
21292
21806
|
try {
|
|
21293
|
-
writeJson(
|
|
21807
|
+
writeJson(join63(runDir(root, runId), "caller.json"), caller);
|
|
21294
21808
|
} catch {
|
|
21295
21809
|
}
|
|
21296
21810
|
const fail3 = (error, code = "provider_unavailable") => {
|
|
@@ -21497,7 +22011,7 @@ Attached saved file references:`);
|
|
|
21497
22011
|
// src/sessions/sideQuestions.ts
|
|
21498
22012
|
import { mkdtemp, rm } from "node:fs/promises";
|
|
21499
22013
|
import { tmpdir as tmpdir8 } from "node:os";
|
|
21500
|
-
import { join as
|
|
22014
|
+
import { join as join64 } from "node:path";
|
|
21501
22015
|
import { z as z6 } from "zod";
|
|
21502
22016
|
init_errors();
|
|
21503
22017
|
init_fs();
|
|
@@ -21557,12 +22071,12 @@ function redactText(value) {
|
|
|
21557
22071
|
const scrubbed = /\b(?:credentials?|private[_-]?key|auth|cookie|secret|password|token|api[_-]?key|client[_-]?id)\b/i.test(redacted) ? String(scrubSensitive(redacted)) : redacted;
|
|
21558
22072
|
return scrubbed.replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]/g, "");
|
|
21559
22073
|
}
|
|
21560
|
-
function bounded2(text10,
|
|
21561
|
-
if (text10.length <=
|
|
22074
|
+
function bounded2(text10, limit2, omitted, fromEnd = false) {
|
|
22075
|
+
if (text10.length <= limit2) return text10;
|
|
21562
22076
|
const marker = `
|
|
21563
22077
|
[${omitted}]
|
|
21564
22078
|
`;
|
|
21565
|
-
const room = Math.max(0,
|
|
22079
|
+
const room = Math.max(0, limit2 - marker.length);
|
|
21566
22080
|
return fromEnd ? `${marker}${text10.slice(-room)}` : `${text10.slice(0, room)}${marker}`;
|
|
21567
22081
|
}
|
|
21568
22082
|
function eventPayload(event) {
|
|
@@ -21698,7 +22212,7 @@ ${note.body}`;
|
|
|
21698
22212
|
return `${reference.label ?? reference.path}: this selected reference is unavailable.`;
|
|
21699
22213
|
}
|
|
21700
22214
|
});
|
|
21701
|
-
const sessionDir = await mkdtemp(
|
|
22215
|
+
const sessionDir = await mkdtemp(join64(tmpdir8(), "xh-side-question-"));
|
|
21702
22216
|
this.sessionDirs.set(runId, sessionDir);
|
|
21703
22217
|
const caller = { ...input.caller, runId, sessionId };
|
|
21704
22218
|
try {
|
|
@@ -21772,13 +22286,13 @@ init_fs();
|
|
|
21772
22286
|
import { createHash as createHash15, randomBytes as randomBytes2 } from "node:crypto";
|
|
21773
22287
|
import { existsSync as existsSync30, mkdirSync as mkdirSync25, realpathSync as realpathSync7, rmSync as rmSync23 } from "node:fs";
|
|
21774
22288
|
import { tmpdir as tmpdir9 } from "node:os";
|
|
21775
|
-
import { basename as basename13, dirname as dirname23, isAbsolute as isAbsolute10, join as
|
|
22289
|
+
import { basename as basename13, dirname as dirname23, isAbsolute as isAbsolute10, join as join66, resolve as resolve11 } from "node:path";
|
|
21776
22290
|
|
|
21777
22291
|
// src/worktrees/copy.ts
|
|
21778
22292
|
init_errors();
|
|
21779
22293
|
init_fs();
|
|
21780
22294
|
import { copyFileSync as copyFileSync5, existsSync as existsSync29, lstatSync as lstatSync14, mkdirSync as mkdirSync24 } from "node:fs";
|
|
21781
|
-
import { dirname as dirname22, join as
|
|
22295
|
+
import { dirname as dirname22, join as join65 } from "node:path";
|
|
21782
22296
|
|
|
21783
22297
|
// src/worktrees/git.ts
|
|
21784
22298
|
init_errors();
|
|
@@ -21877,8 +22391,8 @@ function copyFiles(from, to, paths2) {
|
|
|
21877
22391
|
} catch {
|
|
21878
22392
|
continue;
|
|
21879
22393
|
}
|
|
21880
|
-
const source =
|
|
21881
|
-
const target =
|
|
22394
|
+
const source = join65(from, relative10);
|
|
22395
|
+
const target = join65(to, relative10);
|
|
21882
22396
|
if (existsSync29(target)) {
|
|
21883
22397
|
report.skipped.push({ path: relative10, reason: "exists" });
|
|
21884
22398
|
continue;
|
|
@@ -21931,7 +22445,7 @@ async function ignoredFiles(checkout) {
|
|
|
21931
22445
|
if (pathBytes > IGNORED_PATH_BYTES_CAP) throw ignoredFilesError("the ignored paths exceed the snapshot limit");
|
|
21932
22446
|
let stat;
|
|
21933
22447
|
try {
|
|
21934
|
-
stat = lstatSync14(
|
|
22448
|
+
stat = lstatSync14(join65(checkout, relative10));
|
|
21935
22449
|
} catch {
|
|
21936
22450
|
throw ignoredFilesError(`could not inspect ${relative10}`);
|
|
21937
22451
|
}
|
|
@@ -21946,7 +22460,7 @@ function ignoredFilesError(reason) {
|
|
|
21946
22460
|
return new HarnessError("worktree_has_work", `Ignored files cannot be safely preserved: ${reason}.`, "Move or remove those files, then try again.");
|
|
21947
22461
|
}
|
|
21948
22462
|
async function includedFiles(checkout) {
|
|
21949
|
-
const patterns2 =
|
|
22463
|
+
const patterns2 = join65(checkout, INCLUDE_FILE);
|
|
21950
22464
|
if (!existsSync29(patterns2)) return [];
|
|
21951
22465
|
const ignored = new Set(nulList((await git(checkout, ["ls-files", "--others", "--ignored", "--exclude-standard", "-z"])).stdout));
|
|
21952
22466
|
const matching = nulList((await git(checkout, ["ls-files", "--others", "--ignored", `--exclude-from=${patterns2}`, "-z"])).stdout);
|
|
@@ -21995,11 +22509,11 @@ var Worktrees = class {
|
|
|
21995
22509
|
leaseCounts = /* @__PURE__ */ new Map();
|
|
21996
22510
|
chain = Promise.resolve();
|
|
21997
22511
|
constructor(stateDir, options2 = {}) {
|
|
21998
|
-
this.root = options2.root ??
|
|
22512
|
+
this.root = options2.root ?? join66(stateDir, "worktrees");
|
|
21999
22513
|
this.branchPrefix = options2.branchPrefix ?? "wt/";
|
|
22000
22514
|
this.keep = options2.keep ?? 15;
|
|
22001
|
-
this.registryFile =
|
|
22002
|
-
this.trust = new SetupTrust(
|
|
22515
|
+
this.registryFile = join66(stateDir, "worktrees.json");
|
|
22516
|
+
this.trust = new SetupTrust(join66(stateDir, "worktree-setup-trust.json"));
|
|
22003
22517
|
this.recover(true);
|
|
22004
22518
|
}
|
|
22005
22519
|
// ---- Registry -------------------------------------------------------------------------------
|
|
@@ -22091,15 +22605,15 @@ var Worktrees = class {
|
|
|
22091
22605
|
}
|
|
22092
22606
|
uniqueName(repoRoot, wanted) {
|
|
22093
22607
|
const taken = new Set(this.read().worktrees.filter((record3) => record3.repoRoot === repoRoot && !record3.removed).map((record3) => record3.name));
|
|
22094
|
-
const folder2 =
|
|
22608
|
+
const folder2 = join66(this.root, this.repoKey(repoRoot));
|
|
22095
22609
|
if (wanted !== void 0) {
|
|
22096
22610
|
if (!NAME2.test(wanted)) throw invalid("A worktree name uses lowercase letters, digits and dashes (at most 63).");
|
|
22097
|
-
if (taken.has(wanted) || existsSync30(
|
|
22611
|
+
if (taken.has(wanted) || existsSync30(join66(folder2, wanted))) throw new HarnessError("worktree_exists", `A worktree named ${wanted} already exists.`);
|
|
22098
22612
|
return wanted;
|
|
22099
22613
|
}
|
|
22100
22614
|
for (; ; ) {
|
|
22101
22615
|
const name = `wt-${randomBytes2(3).toString("hex")}`;
|
|
22102
|
-
if (!taken.has(name) && !existsSync30(
|
|
22616
|
+
if (!taken.has(name) && !existsSync30(join66(folder2, name))) return name;
|
|
22103
22617
|
}
|
|
22104
22618
|
}
|
|
22105
22619
|
async branchName(repoRoot, name) {
|
|
@@ -22121,7 +22635,7 @@ var Worktrees = class {
|
|
|
22121
22635
|
const baseCommit = (await git(repoRoot, ["rev-parse", "--verify", "-q", `${baseRef}^{commit}`], { allowFail: true })).stdout.trim();
|
|
22122
22636
|
if (!baseCommit) throw invalid(`${baseRef} does not name a commit.`);
|
|
22123
22637
|
const branch = input.branch ? await this.branchName(repoRoot, input.branch) : null;
|
|
22124
|
-
const path4 =
|
|
22638
|
+
const path4 = join66(this.root, this.repoKey(repoRoot), name);
|
|
22125
22639
|
mkdirSync25(dirname23(path4), { recursive: true });
|
|
22126
22640
|
await git(repoRoot, ["worktree", "add", ...branch ? ["-b", branch] : ["--detach"], path4, baseCommit]);
|
|
22127
22641
|
const at = now();
|
|
@@ -22151,7 +22665,7 @@ var Worktrees = class {
|
|
|
22151
22665
|
carried = copyFiles(repoRoot, path4, await untrackedFiles(repoRoot));
|
|
22152
22666
|
}
|
|
22153
22667
|
const included = copyFiles(repoRoot, path4, await includedFiles(repoRoot));
|
|
22154
|
-
const setup = input.setup === false ? { state: "none", hash: null, log: null } : await runSetup({ checkout: path4, source: repoRoot, name, repoRoot, logFile:
|
|
22668
|
+
const setup = input.setup === false ? { state: "none", hash: null, log: null } : await runSetup({ checkout: path4, source: repoRoot, name, repoRoot, logFile: join66(this.root, "logs", `${record3.id}.setup.log`), trust: this.trust });
|
|
22155
22669
|
return { worktree: record3, carried: { ...carried, patched }, included, setup };
|
|
22156
22670
|
});
|
|
22157
22671
|
}
|
|
@@ -22258,7 +22772,7 @@ var Worktrees = class {
|
|
|
22258
22772
|
}
|
|
22259
22773
|
/** Records the worktree's commits and working changes under a snapshot ref. */
|
|
22260
22774
|
async snapshot(record3, ignored) {
|
|
22261
|
-
const index =
|
|
22775
|
+
const index = join66(tmpdir9(), `xharness-index-${record3.id}-${randomBytes2(4).toString("hex")}`);
|
|
22262
22776
|
const env = { ...IDENTITY, GIT_INDEX_FILE: index };
|
|
22263
22777
|
try {
|
|
22264
22778
|
await git(record3.path, ["read-tree", "HEAD"], { env });
|
|
@@ -22373,7 +22887,7 @@ var Worktrees = class {
|
|
|
22373
22887
|
if (dirty) throw new HarnessError("handoff_target_dirty", `The ${direction === "toSource" ? "main checkout" : "worktree"} has uncommitted changes.`, "Commit or stash them, then hand off again.");
|
|
22374
22888
|
const patch = (await git(origin3, ["diff", "--binary", direction === "toSource" ? record3.baseCommit : "HEAD"])).stdout;
|
|
22375
22889
|
const untracked = await untrackedFiles(origin3);
|
|
22376
|
-
const collisions = untracked.filter((path4) => existsSync30(
|
|
22890
|
+
const collisions = untracked.filter((path4) => existsSync30(join66(target, path4)));
|
|
22377
22891
|
if (collisions.length) throw new HarnessError("handoff_conflict", `${collisions.length} untracked file(s) already exist in the target, for example ${collisions[0]}.`);
|
|
22378
22892
|
if (patch.trim()) {
|
|
22379
22893
|
const check2 = await git(target, ["apply", "--check", "--binary", "--whitespace=nowarn"], { input: patch, allowFail: true });
|
|
@@ -22660,12 +23174,12 @@ var SUM = `COUNT(*) AS requests, SUM(input_tokens) AS input, SUM(cache_read_toke
|
|
|
22660
23174
|
SUM(cache_write_tokens) AS cacheWrite, SUM(output_tokens) AS output, SUM(reasoning_tokens) AS reasoning,
|
|
22661
23175
|
SUM(cost_usd) AS cost, SUM(CASE WHEN cost_usd IS NULL THEN 1 ELSE 0 END) AS unpriced,
|
|
22662
23176
|
AVG(ttft_ms) AS ttft, AVG(duration_ms) AS duration`;
|
|
22663
|
-
function grouped(database, column, clause, params,
|
|
23177
|
+
function grouped(database, column, clause, params, limit2) {
|
|
22664
23178
|
return all(
|
|
22665
23179
|
database,
|
|
22666
23180
|
`SELECT ${column} AS key, ${SUM} FROM usage_requests WHERE ${clause}
|
|
22667
23181
|
GROUP BY ${column} ORDER BY SUM(COALESCE(input_tokens,0)+COALESCE(cache_read_tokens,0)+COALESCE(cache_write_tokens,0)+COALESCE(output_tokens,0)) DESC
|
|
22668
|
-
LIMIT ${
|
|
23182
|
+
LIMIT ${limit2}`,
|
|
22669
23183
|
...params
|
|
22670
23184
|
).map((row) => ({ key: row.key ?? "", values: row }));
|
|
22671
23185
|
}
|
|
@@ -22888,8 +23402,8 @@ function toIso(value, now2) {
|
|
|
22888
23402
|
}
|
|
22889
23403
|
var leftPercent = (usedPercent) => usedPercent === null ? null : Math.max(0, Math.min(100, 100 - usedPercent));
|
|
22890
23404
|
var statusFor = (percent2, fallback = "allowed") => percent2 === null ? fallback : percent2 >= 100 ? "rejected" : percent2 >= 80 ? "warning" : "allowed";
|
|
22891
|
-
function entry(
|
|
22892
|
-
return { ...
|
|
23405
|
+
function entry(limit2, observedAt) {
|
|
23406
|
+
return { ...limit2, provider: limit2.provider, observedAt };
|
|
22893
23407
|
}
|
|
22894
23408
|
var ANTHROPIC_FAMILIES = [
|
|
22895
23409
|
{ key: "requests", label: "Requests", unit: "requests" },
|
|
@@ -22902,17 +23416,17 @@ function normalizeHeaders(provider, response, now2 = /* @__PURE__ */ new Date())
|
|
|
22902
23416
|
const headers = headersOf(response.headers);
|
|
22903
23417
|
const observedAt = now2.toISOString();
|
|
22904
23418
|
const limits = /* @__PURE__ */ new Map();
|
|
22905
|
-
const put2 = (
|
|
22906
|
-
limits.set(
|
|
23419
|
+
const put2 = (limit2) => {
|
|
23420
|
+
limits.set(limit2.id, limit2);
|
|
22907
23421
|
};
|
|
22908
23422
|
for (const family of ANTHROPIC_FAMILIES) {
|
|
22909
23423
|
const prefix = `anthropic-ratelimit-${family.key}-`;
|
|
22910
|
-
const
|
|
23424
|
+
const limit2 = toNumber(headers.get(`${prefix}limit`));
|
|
22911
23425
|
const remaining = toNumber(headers.get(`${prefix}remaining`));
|
|
22912
23426
|
const resetsAt = toIso(headers.get(`${prefix}reset`), now2);
|
|
22913
|
-
if (
|
|
22914
|
-
const used =
|
|
22915
|
-
const usedPercent =
|
|
23427
|
+
if (limit2 === null && remaining === null && !resetsAt) continue;
|
|
23428
|
+
const used = limit2 !== null && remaining !== null ? Math.max(0, limit2 - remaining) : null;
|
|
23429
|
+
const usedPercent = limit2 !== null && limit2 > 0 && used !== null ? used / limit2 * 100 : null;
|
|
22916
23430
|
put2(entry({
|
|
22917
23431
|
id: `${provider}:${family.key}`,
|
|
22918
23432
|
label: family.label,
|
|
@@ -22920,7 +23434,7 @@ function normalizeHeaders(provider, response, now2 = /* @__PURE__ */ new Date())
|
|
|
22920
23434
|
kind: "rate",
|
|
22921
23435
|
unit: family.unit,
|
|
22922
23436
|
used,
|
|
22923
|
-
limit,
|
|
23437
|
+
limit: limit2,
|
|
22924
23438
|
remaining,
|
|
22925
23439
|
usedPercent,
|
|
22926
23440
|
remainingPercent: leftPercent(usedPercent),
|
|
@@ -22985,12 +23499,12 @@ function normalizeHeaders(provider, response, now2 = /* @__PURE__ */ new Date())
|
|
|
22985
23499
|
}
|
|
22986
23500
|
for (const [family, bucket] of families) {
|
|
22987
23501
|
if (!RATE_FAMILIES.includes(family)) continue;
|
|
22988
|
-
const
|
|
23502
|
+
const limit2 = toNumber(bucket.limit);
|
|
22989
23503
|
const remaining = toNumber(bucket.remaining);
|
|
22990
23504
|
const resetsAt = toIso(bucket.reset, now2);
|
|
22991
|
-
if (
|
|
22992
|
-
const used =
|
|
22993
|
-
const usedPercent =
|
|
23505
|
+
if (limit2 === null && remaining === null && !resetsAt) continue;
|
|
23506
|
+
const used = limit2 !== null && remaining !== null ? Math.max(0, limit2 - remaining) : null;
|
|
23507
|
+
const usedPercent = limit2 !== null && limit2 > 0 && used !== null ? used / limit2 * 100 : null;
|
|
22994
23508
|
put2(entry({
|
|
22995
23509
|
id: `${provider}:rate-${family}`,
|
|
22996
23510
|
label: `${title(family)} (rate)`,
|
|
@@ -22998,7 +23512,7 @@ function normalizeHeaders(provider, response, now2 = /* @__PURE__ */ new Date())
|
|
|
22998
23512
|
kind: "rate",
|
|
22999
23513
|
unit: family.includes("token") ? "tokens" : "requests",
|
|
23000
23514
|
used,
|
|
23001
|
-
limit,
|
|
23515
|
+
limit: limit2,
|
|
23002
23516
|
remaining,
|
|
23003
23517
|
usedPercent,
|
|
23004
23518
|
remainingPercent: leftPercent(usedPercent),
|
|
@@ -23027,8 +23541,8 @@ function normalizeHeaders(provider, response, now2 = /* @__PURE__ */ new Date())
|
|
|
23027
23541
|
}
|
|
23028
23542
|
|
|
23029
23543
|
// src/usage/limits/adapters.ts
|
|
23030
|
-
var providerEntry = (provider, observedAt,
|
|
23031
|
-
var percent = (used,
|
|
23544
|
+
var providerEntry = (provider, observedAt, limit2) => ({ ...limit2, provider, observedAt, source: "provider" });
|
|
23545
|
+
var percent = (used, limit2) => limit2 > 0 ? Math.min(100, Math.max(0, used / limit2 * 100)) : null;
|
|
23032
23546
|
var OPENROUTER_ADAPTER = {
|
|
23033
23547
|
id: "openrouter-key",
|
|
23034
23548
|
providers: ["openrouter"],
|
|
@@ -23041,21 +23555,21 @@ var OPENROUTER_ADAPTER = {
|
|
|
23041
23555
|
if (!data || typeof data !== "object") return { limits: [], reason: "OpenRouter returned no key details." };
|
|
23042
23556
|
const observedAt = now2.toISOString();
|
|
23043
23557
|
const limits = [];
|
|
23044
|
-
const
|
|
23558
|
+
const limit2 = typeof data.limit === "number" ? data.limit : null;
|
|
23045
23559
|
const remaining = typeof data.limit_remaining === "number" ? data.limit_remaining : null;
|
|
23046
|
-
if (
|
|
23047
|
-
const used = Math.max(0,
|
|
23560
|
+
if (limit2 !== null && remaining !== null) {
|
|
23561
|
+
const used = Math.max(0, limit2 - remaining);
|
|
23048
23562
|
limits.push(providerEntry(provider, observedAt, {
|
|
23049
23563
|
id: `${provider}:key-credits`,
|
|
23050
23564
|
label: "Key credits",
|
|
23051
23565
|
kind: "credit",
|
|
23052
23566
|
unit: "usd",
|
|
23053
23567
|
used,
|
|
23054
|
-
limit,
|
|
23568
|
+
limit: limit2,
|
|
23055
23569
|
remaining,
|
|
23056
|
-
usedPercent: percent(used,
|
|
23057
|
-
remainingPercent: percent(remaining,
|
|
23058
|
-
status: remaining <= 0 ? "rejected" : percent(used,
|
|
23570
|
+
usedPercent: percent(used, limit2),
|
|
23571
|
+
remainingPercent: percent(remaining, limit2),
|
|
23572
|
+
status: remaining <= 0 ? "rejected" : percent(used, limit2) >= 80 ? "warning" : "allowed"
|
|
23059
23573
|
}));
|
|
23060
23574
|
}
|
|
23061
23575
|
const budgets = Array.isArray(data.budgets) ? data.budgets : [];
|
|
@@ -23427,10 +23941,10 @@ var UsageLimits = class {
|
|
|
23427
23941
|
accounts: accounts.map((account) => {
|
|
23428
23942
|
const known = /* @__PURE__ */ new Map();
|
|
23429
23943
|
for (const entry2 of account.state.providerLimits ?? []) known.set(entry2.provider, entry2);
|
|
23430
|
-
for (const
|
|
23431
|
-
const provider =
|
|
23944
|
+
for (const limit2 of account.state.limits) {
|
|
23945
|
+
const provider = limit2.provider;
|
|
23432
23946
|
if (!provider || known.has(provider)) continue;
|
|
23433
|
-
known.set(provider, { source:
|
|
23947
|
+
known.set(provider, { source: limit2.source === "provider" ? "provider" : "headers", reason: null, observedAt: limit2.observedAt ?? this.now().toISOString() });
|
|
23434
23948
|
}
|
|
23435
23949
|
return {
|
|
23436
23950
|
accountId: account.id,
|
|
@@ -23442,7 +23956,7 @@ var UsageLimits = class {
|
|
|
23442
23956
|
source: entry2.source,
|
|
23443
23957
|
reason: entry2.reason,
|
|
23444
23958
|
observedAt: entry2.observedAt,
|
|
23445
|
-
limits: account.state.limits.filter((
|
|
23959
|
+
limits: account.state.limits.filter((limit2) => limit2.provider === provider && !(limit2.resetsAt && Date.parse(limit2.resetsAt) <= this.now().getTime()))
|
|
23446
23960
|
})).sort((left, right) => left.provider.localeCompare(right.provider))
|
|
23447
23961
|
};
|
|
23448
23962
|
})
|
|
@@ -23506,7 +24020,7 @@ var UsageLimits = class {
|
|
|
23506
24020
|
const reading = await adapter.read(context);
|
|
23507
24021
|
this.options.accounts.applyLimits(account.id, [{
|
|
23508
24022
|
provider,
|
|
23509
|
-
limits: reading.limits.map((
|
|
24023
|
+
limits: reading.limits.map((limit2) => ({ ...limit2, provider, observedAt, source: "provider" })),
|
|
23510
24024
|
source: "provider",
|
|
23511
24025
|
reason: reading.reason ? scrub(reading.reason) : null,
|
|
23512
24026
|
observedAt,
|
|
@@ -23518,23 +24032,23 @@ var UsageLimits = class {
|
|
|
23518
24032
|
}
|
|
23519
24033
|
/** Limits known for one account and provider, for diagnostics. */
|
|
23520
24034
|
limitsOf(accountId, provider) {
|
|
23521
|
-
return this.options.accounts.overview().accounts.find((account) => account.id === accountId)?.state.limits.filter((
|
|
24035
|
+
return this.options.accounts.overview().accounts.find((account) => account.id === accountId)?.state.limits.filter((limit2) => limit2.provider === provider) ?? [];
|
|
23522
24036
|
}
|
|
23523
24037
|
};
|
|
23524
24038
|
|
|
23525
24039
|
// src/annotations/capture.ts
|
|
23526
24040
|
import { spawn as spawn6 } from "node:child_process";
|
|
23527
24041
|
import { randomUUID as randomUUID18 } from "node:crypto";
|
|
23528
|
-
import { existsSync as existsSync32, readdirSync as
|
|
24042
|
+
import { existsSync as existsSync32, readdirSync as readdirSync29, statSync as statSync22 } from "node:fs";
|
|
23529
24043
|
import { createServer as createServer4 } from "node:net";
|
|
23530
|
-
import { basename as basename14, join as
|
|
24044
|
+
import { basename as basename14, join as join68 } from "node:path";
|
|
23531
24045
|
|
|
23532
24046
|
// src/annotations/bridge.ts
|
|
23533
24047
|
init_fs();
|
|
23534
24048
|
import { randomBytes as randomBytes3 } from "node:crypto";
|
|
23535
24049
|
import { chmodSync as chmodSync14, existsSync as existsSync31 } from "node:fs";
|
|
23536
24050
|
import { createServer as createServer3 } from "node:http";
|
|
23537
|
-
import { join as
|
|
24051
|
+
import { join as join67 } from "node:path";
|
|
23538
24052
|
var POLL_MS = 2e4;
|
|
23539
24053
|
var GONE_MS = 45e3;
|
|
23540
24054
|
var CALL_MS = 1e4;
|
|
@@ -23587,7 +24101,7 @@ var NotesBridge = class {
|
|
|
23587
24101
|
nextWindow = 1;
|
|
23588
24102
|
nextCall = 1;
|
|
23589
24103
|
settingsFile() {
|
|
23590
|
-
return
|
|
24104
|
+
return join67(this.options.stateDir, "notes-bridge.json");
|
|
23591
24105
|
}
|
|
23592
24106
|
/** Starts the bridge (once) on the port and token kept from last time, so the app's snippet stays valid. */
|
|
23593
24107
|
start() {
|
|
@@ -23845,13 +24359,13 @@ var freePort = () => new Promise((resolve19, reject2) => {
|
|
|
23845
24359
|
});
|
|
23846
24360
|
function appExecutable(path4) {
|
|
23847
24361
|
if (!/\.app\/?$/.test(path4)) return path4;
|
|
23848
|
-
const folder2 =
|
|
24362
|
+
const folder2 = join68(path4, "Contents", "MacOS");
|
|
23849
24363
|
if (!existsSync32(folder2)) throw new Error(`${path4} has no Contents/MacOS folder.`);
|
|
23850
|
-
const programs =
|
|
24364
|
+
const programs = readdirSync29(folder2).filter((name) => !name.startsWith(".") && statSync22(join68(folder2, name)).isFile());
|
|
23851
24365
|
const named2 = basename14(path4.replace(/\/$/, ""), ".app");
|
|
23852
24366
|
const program = programs.find((name) => name === named2) ?? programs[0];
|
|
23853
24367
|
if (!program) throw new Error(`${path4} has no program in Contents/MacOS.`);
|
|
23854
|
-
return
|
|
24368
|
+
return join68(folder2, program);
|
|
23855
24369
|
}
|
|
23856
24370
|
function describeApp(port, version2, list7) {
|
|
23857
24371
|
const agent = typeof version2["User-Agent"] === "string" ? version2["User-Agent"] : "";
|
|
@@ -23983,8 +24497,8 @@ var AnnotationCapture = class {
|
|
|
23983
24497
|
if (existing instanceof WebTarget) return existing;
|
|
23984
24498
|
const session = new BrowserSession({
|
|
23985
24499
|
key: `notes-${key}`,
|
|
23986
|
-
profileDir:
|
|
23987
|
-
downloadsDir:
|
|
24500
|
+
profileDir: join68(this.options.stateDir, "browser", "profiles", "person"),
|
|
24501
|
+
downloadsDir: join68(this.options.stateDir, "browser", "downloads", fileName(`notes-${key}`)),
|
|
23988
24502
|
// Always a window the person can see and select in.
|
|
23989
24503
|
config: () => ({ ...readBrowserConfig(this.options.stateDir), headed: true }),
|
|
23990
24504
|
network: this.network,
|
|
@@ -24419,7 +24933,7 @@ var Harness = class {
|
|
|
24419
24933
|
this.browserEnabled = options2.browser !== false;
|
|
24420
24934
|
this.stateDir = options2.stateDir;
|
|
24421
24935
|
mkdirSync26(this.stateDir, { recursive: true });
|
|
24422
|
-
isolateProcess(
|
|
24936
|
+
isolateProcess(join69(this.stateDir, "accounts"));
|
|
24423
24937
|
this.env = new Env(options2.dataRoot || null, options2.directory ?? EMPTY_DIRECTORY, options2.productName ?? DEFAULT_PRODUCT_NAME, this.bus);
|
|
24424
24938
|
this.hub = new Hub(this, options2.hub);
|
|
24425
24939
|
this.policy = options2.policy ?? {};
|
|
@@ -24427,8 +24941,8 @@ var Harness = class {
|
|
|
24427
24941
|
configureBuiltins(options2.builtins ?? []);
|
|
24428
24942
|
this.trust = new VariantTrust(this.stateDir);
|
|
24429
24943
|
this.refineHost = options2.refineHost ?? null;
|
|
24430
|
-
const secrets = options2.secrets ?? fileSecretStore(
|
|
24431
|
-
this.accounts = new Accounts({ dir:
|
|
24944
|
+
const secrets = options2.secrets ?? fileSecretStore(join69(this.stateDir, "secrets.json"));
|
|
24945
|
+
this.accounts = new Accounts({ dir: join69(this.stateDir, "accounts"), secrets, bus: this.bus });
|
|
24432
24946
|
this.approvals = new Approvals(this.stateDir, this.bus);
|
|
24433
24947
|
this.usageLimits = new UsageLimits({ accounts: this.accounts, root: () => this.env.dataRoot });
|
|
24434
24948
|
this.accounts.observeModels = (models, accountId) => this.usageLimits.observeModels(models, accountId);
|
|
@@ -24443,7 +24957,7 @@ var Harness = class {
|
|
|
24443
24957
|
ended: (runId, sessionId) => this.apps.revokeRun(runId, sessionId)
|
|
24444
24958
|
});
|
|
24445
24959
|
this.apps = new ConnectedApps({ env: this.env, stateDir: this.stateDir, secrets, bus: this.bus, runs: this.runs, policy: this.policy, oauthClients: options2.oauthClients });
|
|
24446
|
-
this.plugins = new Plugins({ stateDir: this.stateDir, bus: this.bus, resolver: options2.resolver, attachments: () => this.env.dataRoot ? load3(this.env.dataRoot) : null, packagesDir: () => this.env.dataRoot ?
|
|
24960
|
+
this.plugins = new Plugins({ stateDir: this.stateDir, bus: this.bus, resolver: options2.resolver, attachments: () => this.env.dataRoot ? load3(this.env.dataRoot) : null, packagesDir: () => this.env.dataRoot ? join69(this.env.dataRoot, "plugins") : null });
|
|
24447
24961
|
this.hooks = new Hooks({
|
|
24448
24962
|
stateDir: this.stateDir,
|
|
24449
24963
|
bus: this.bus,
|
|
@@ -24451,9 +24965,9 @@ var Harness = class {
|
|
|
24451
24965
|
// The shared folder stands in for an account: packages are the same for all of them.
|
|
24452
24966
|
wanted: async () => {
|
|
24453
24967
|
if (!this.env.dataRoot) return [];
|
|
24454
|
-
const shared = ensureSharedDir(
|
|
24455
|
-
const named2 = readJsonOr(
|
|
24456
|
-
if (!packageFolders(
|
|
24968
|
+
const shared = ensureSharedDir(join69(this.stateDir, "accounts"));
|
|
24969
|
+
const named2 = readJsonOr(join69(shared, "settings.json"), {}).packages;
|
|
24970
|
+
if (!packageFolders(join69(this.env.dataRoot, "plugins")).length && !(Array.isArray(named2) && named2.length)) return [];
|
|
24457
24971
|
return (await this.plugins.loading({ cwd: this.stateDir, agentDir: shared, caller: {} })).hooks;
|
|
24458
24972
|
},
|
|
24459
24973
|
call: (connection, tool, args) => this.apps.callUnattended(connection, tool, args ?? {}),
|
|
@@ -24538,7 +25052,7 @@ var Harness = class {
|
|
|
24538
25052
|
const root = dataRoot;
|
|
24539
25053
|
this.hooks.watch(wikiDir(root));
|
|
24540
25054
|
void this.hooks.reload();
|
|
24541
|
-
for (const folder2 of ["registry/skills", "registry/prompts", "registry/rules", "config", "runs"]) mkdirSync26(
|
|
25055
|
+
for (const folder2 of ["registry/skills", "registry/prompts", "registry/rules", "config", "runs"]) mkdirSync26(join69(root, folder2), { recursive: true });
|
|
24542
25056
|
let migrationError = null;
|
|
24543
25057
|
try {
|
|
24544
25058
|
const moved = migrateVariantLayout(root);
|
|
@@ -24547,7 +25061,7 @@ var Harness = class {
|
|
|
24547
25061
|
migrationError = error instanceof Error ? error.message : String(error);
|
|
24548
25062
|
log("variant layout", migrationError);
|
|
24549
25063
|
}
|
|
24550
|
-
mkdirSync26(
|
|
25064
|
+
mkdirSync26(join69(root, "variants"), { recursive: true });
|
|
24551
25065
|
let legacyWiki = null;
|
|
24552
25066
|
try {
|
|
24553
25067
|
legacyWiki = moveLegacy(root);
|
|
@@ -24644,7 +25158,7 @@ function createHarness(options2) {
|
|
|
24644
25158
|
|
|
24645
25159
|
// src/plugins/cli.ts
|
|
24646
25160
|
import { homedir as homedir6 } from "node:os";
|
|
24647
|
-
import { join as
|
|
25161
|
+
import { join as join70, resolve as resolve12 } from "node:path";
|
|
24648
25162
|
import { createInterface } from "node:readline/promises";
|
|
24649
25163
|
var PLUGINS_USAGE = `Usage: xagent plugins <command> [options]
|
|
24650
25164
|
|
|
@@ -24710,8 +25224,8 @@ async function runPluginsCli(argv, dependencies = {}) {
|
|
|
24710
25224
|
return command ? 0 : 2;
|
|
24711
25225
|
}
|
|
24712
25226
|
const base = dependencies.cwd ?? process.cwd();
|
|
24713
|
-
const root =
|
|
24714
|
-
const options2 = { dataRoot: parsed.values.data ? resolve12(base, parsed.values.data) :
|
|
25227
|
+
const root = join70(dependencies.home ?? homedir6(), ".xingular-harness");
|
|
25228
|
+
const options2 = { dataRoot: parsed.values.data ? resolve12(base, parsed.values.data) : join70(root, "data"), stateDir: parsed.values.state ? resolve12(base, parsed.values.state) : join70(root, "state"), productName: DEFAULT_PRODUCT_NAME };
|
|
24715
25229
|
const harness = dependencies.createHarness ? dependencies.createHarness(options2) : new Harness(options2);
|
|
24716
25230
|
const scope = { cwd: parsed.values.cwd ? resolve12(base, parsed.values.cwd) : null };
|
|
24717
25231
|
const need = (what) => {
|
|
@@ -24824,7 +25338,7 @@ function terminalAsk() {
|
|
|
24824
25338
|
|
|
24825
25339
|
// src/hub/cli.ts
|
|
24826
25340
|
import { homedir as homedir7 } from "node:os";
|
|
24827
|
-
import { join as
|
|
25341
|
+
import { join as join71, resolve as resolve13 } from "node:path";
|
|
24828
25342
|
var HUB_USAGE = `Usage: xagent hub <list | show | install> [id@version] [options]
|
|
24829
25343
|
|
|
24830
25344
|
list [--refresh] Browse the curated catalog and locally installed versions
|
|
@@ -24866,8 +25380,8 @@ async function runHubCli(argv, dependencies = {}) {
|
|
|
24866
25380
|
write4(HUB_USAGE);
|
|
24867
25381
|
return 2;
|
|
24868
25382
|
}
|
|
24869
|
-
const root =
|
|
24870
|
-
const options2 = { dataRoot: values2.data ??
|
|
25383
|
+
const root = join71(dependencies.home ?? homedir7(), ".xingular-harness");
|
|
25384
|
+
const options2 = { dataRoot: values2.data ?? join71(root, "data"), stateDir: values2.state ?? join71(root, "state") };
|
|
24871
25385
|
const harness = dependencies.createHarness?.(options2) ?? new Harness(options2);
|
|
24872
25386
|
try {
|
|
24873
25387
|
const overview2 = await harness.hub.list(refresh);
|
|
@@ -24911,15 +25425,15 @@ Delivery: ${JSON.stringify(delivery)}
|
|
|
24911
25425
|
|
|
24912
25426
|
// src/refine/cli.ts
|
|
24913
25427
|
init_fs();
|
|
24914
|
-
import { mkdtempSync as mkdtempSync10, readFileSync as
|
|
25428
|
+
import { mkdtempSync as mkdtempSync10, readFileSync as readFileSync34 } from "node:fs";
|
|
24915
25429
|
import { homedir as homedir8, tmpdir as tmpdir11 } from "node:os";
|
|
24916
|
-
import { basename as basename15, join as
|
|
25430
|
+
import { basename as basename15, join as join74, resolve as resolve14 } from "node:path";
|
|
24917
25431
|
|
|
24918
25432
|
// src/refine/demo.ts
|
|
24919
25433
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
24920
|
-
import { cpSync as cpSync5, existsSync as existsSync33, mkdirSync as mkdirSync27, mkdtempSync as mkdtempSync9, readdirSync as
|
|
25434
|
+
import { cpSync as cpSync5, existsSync as existsSync33, mkdirSync as mkdirSync27, mkdtempSync as mkdtempSync9, readdirSync as readdirSync30, readFileSync as readFileSync32, writeFileSync as writeFileSync12 } from "node:fs";
|
|
24921
25435
|
import { tmpdir as tmpdir10 } from "node:os";
|
|
24922
|
-
import { join as
|
|
25436
|
+
import { join as join72 } from "node:path";
|
|
24923
25437
|
var DEMO_SCRIPT = `import { readFileSync } from 'node:fs'
|
|
24924
25438
|
|
|
24925
25439
|
const rows = readFileSync(process.argv[2], 'utf8').trim().split('\\n').slice(1)
|
|
@@ -24942,11 +25456,11 @@ var DEMO_LEDGERS = {
|
|
|
24942
25456
|
};
|
|
24943
25457
|
function demoTasks(root, scope = "demo") {
|
|
24944
25458
|
return Object.entries(DEMO_LEDGERS).map(([id, amounts]) => {
|
|
24945
|
-
const sourceDir =
|
|
25459
|
+
const sourceDir = join72(root, "sources", id);
|
|
24946
25460
|
mkdirSync27(sourceDir, { recursive: true });
|
|
24947
|
-
writeFileSync12(
|
|
25461
|
+
writeFileSync12(join72(sourceDir, "ledger.csv"), `amount
|
|
24948
25462
|
${amounts}`);
|
|
24949
|
-
writeFileSync12(
|
|
25463
|
+
writeFileSync12(join72(sourceDir, "reference_answer.txt"), "never shown to a model");
|
|
24950
25464
|
return {
|
|
24951
25465
|
id,
|
|
24952
25466
|
scope,
|
|
@@ -24966,25 +25480,25 @@ var DemoExecutor = class {
|
|
|
24966
25480
|
executions = 0;
|
|
24967
25481
|
async execute(task, variantDir, label, runId) {
|
|
24968
25482
|
this.executions++;
|
|
24969
|
-
const dir2 =
|
|
25483
|
+
const dir2 = join72(this.root, "executions", runId);
|
|
24970
25484
|
mkdirSync27(dir2, { recursive: true });
|
|
24971
|
-
const script =
|
|
24972
|
-
const result = spawnSync3(process.execPath, [script,
|
|
25485
|
+
const script = join72(variantDir ?? "", "scripts", "summarize.mjs");
|
|
25486
|
+
const result = spawnSync3(process.execPath, [script, join72(task.sourceDir ?? "", "ledger.csv")], { encoding: "utf8", timeout: 1e4 });
|
|
24973
25487
|
if (result.status !== 0) {
|
|
24974
25488
|
return { label, runId, dir: dir2, ok: false, delivered: false, costUsd: 0, wallMs: 0, error: result.stderr || "script failed" };
|
|
24975
25489
|
}
|
|
24976
|
-
writeFileSync12(
|
|
24977
|
-
writeFileSync12(
|
|
25490
|
+
writeFileSync12(join72(dir2, "answer.txt"), result.stdout);
|
|
25491
|
+
writeFileSync12(join72(dir2, "trajectory.md"), `[ACTION] Run scripts/summarize.mjs on ledger.csv
|
|
24978
25492
|
[OBSERVATION]
|
|
24979
25493
|
${result.stdout}`);
|
|
24980
25494
|
return { label, runId, dir: dir2, ok: true, delivered: true, costUsd: 0, wallMs: 0, error: "" };
|
|
24981
25495
|
}
|
|
24982
25496
|
trajectory(rollout) {
|
|
24983
|
-
return
|
|
25497
|
+
return readFileSync32(join72(rollout.dir, "trajectory.md"), "utf8");
|
|
24984
25498
|
}
|
|
24985
25499
|
deliverableFiles(rollout) {
|
|
24986
|
-
const path4 =
|
|
24987
|
-
return existsSync33(path4) ? { "answer.txt":
|
|
25500
|
+
const path4 = join72(rollout.dir, "answer.txt");
|
|
25501
|
+
return existsSync33(path4) ? { "answer.txt": readFileSync32(path4, "utf8") } : {};
|
|
24988
25502
|
}
|
|
24989
25503
|
validateVariant(_task, variant) {
|
|
24990
25504
|
if (!variant["scripts/summarize.mjs"]) throw new Error("The local executor requires scripts/summarize.mjs");
|
|
@@ -25002,15 +25516,15 @@ var DemoImprover = class {
|
|
|
25002
25516
|
let workspace = null;
|
|
25003
25517
|
let text10;
|
|
25004
25518
|
if (input.label.startsWith("select.")) {
|
|
25005
|
-
const expected = `Total: ${signedTotal(
|
|
25006
|
-
const ids2 =
|
|
25007
|
-
const chosen = ids2.find((name) =>
|
|
25519
|
+
const expected = `Total: ${signedTotal(readFileSync32(join72(context, "source", "ledger.csv"), "utf8"))}`;
|
|
25520
|
+
const ids2 = readdirSync30(join72(context, "candidates")).filter((name) => name.endsWith(".md")).sort();
|
|
25521
|
+
const chosen = ids2.find((name) => readFileSync32(join72(context, "candidates", name), "utf8").includes(expected))?.replace(/\.md$/, "") ?? ids2[0].replace(/\.md$/, "");
|
|
25008
25522
|
text10 = `<why>The signed total matches the source ledger.</why>
|
|
25009
25523
|
\`\`\`choice
|
|
25010
25524
|
${chosen}
|
|
25011
25525
|
\`\`\``;
|
|
25012
25526
|
} else if (input.label.startsWith("experience.")) {
|
|
25013
|
-
const changed2 =
|
|
25527
|
+
const changed2 = readFileSync32(join72(context, "harness", "scripts", "summarize.mjs"), "utf8") !== readFileSync32(join72(context, "base_harness", "scripts", "summarize.mjs"), "utf8");
|
|
25014
25528
|
text10 = `<edits>
|
|
25015
25529
|
component: scripts/summarize.mjs
|
|
25016
25530
|
candidates: inv1
|
|
@@ -25021,10 +25535,10 @@ verdict: ${changed2 ? "helped" : "no observed effect"}
|
|
|
25021
25535
|
|
|
25022
25536
|
` + (changed2 ? "<experience>\ncue: When a ledger includes credits and debits\nlesson: Include both signs when summing in scripts/summarize.mjs.\nevidence: The scripts/summarize.mjs row -- removing the positive-only filter changed the probe total to include the credits omitted by the base trajectory.\nconfidence: high for this observed arithmetic contrast\n</experience>" : "NO_ENTRY");
|
|
25023
25537
|
} else {
|
|
25024
|
-
workspace = mkdtempSync9(
|
|
25025
|
-
cpSync5(
|
|
25026
|
-
const script =
|
|
25027
|
-
writeFileSync12(script,
|
|
25538
|
+
workspace = mkdtempSync9(join72(tmpdir10(), "harness-demo-"));
|
|
25539
|
+
cpSync5(join72(context, "harness"), workspace, { recursive: true });
|
|
25540
|
+
const script = join72(workspace, "scripts", "summarize.mjs");
|
|
25541
|
+
writeFileSync12(script, readFileSync32(script, "utf8").replace(".filter((amount) => amount > 0)", ""));
|
|
25028
25542
|
text10 = "<notes>Keep signed amounts: the base total omitted credits in the source ledger.</notes>";
|
|
25029
25543
|
}
|
|
25030
25544
|
return { label: input.label, text: text10, costUsd: 0, attempts: 1, cached: false, workspace };
|
|
@@ -25034,11 +25548,11 @@ verdict: ${changed2 ? "helped" : "no observed effect"}
|
|
|
25034
25548
|
// src/refine/suite.ts
|
|
25035
25549
|
init_fs();
|
|
25036
25550
|
import { createHash as createHash16 } from "node:crypto";
|
|
25037
|
-
import { existsSync as existsSync34, readFileSync as
|
|
25038
|
-
import { dirname as dirname24, join as
|
|
25551
|
+
import { existsSync as existsSync34, readFileSync as readFileSync33 } from "node:fs";
|
|
25552
|
+
import { dirname as dirname24, join as join73 } from "node:path";
|
|
25039
25553
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
25040
25554
|
function matrixDir(root, id) {
|
|
25041
|
-
return
|
|
25555
|
+
return join73(root, "refine", safeId(id));
|
|
25042
25556
|
}
|
|
25043
25557
|
var packageVersionMemo = null;
|
|
25044
25558
|
function packageVersion() {
|
|
@@ -25048,9 +25562,9 @@ function packageVersion() {
|
|
|
25048
25562
|
let dir2 = fileURLToPath3(import.meta.url);
|
|
25049
25563
|
for (let up = 0; up < 6; up++) {
|
|
25050
25564
|
dir2 = dirname24(dir2);
|
|
25051
|
-
const manifest =
|
|
25565
|
+
const manifest = join73(dir2, "package.json");
|
|
25052
25566
|
if (existsSync34(manifest)) {
|
|
25053
|
-
const json2 = JSON.parse(
|
|
25567
|
+
const json2 = JSON.parse(readFileSync33(manifest, "utf8"));
|
|
25054
25568
|
if (json2.version) packageVersionMemo = json2.version;
|
|
25055
25569
|
break;
|
|
25056
25570
|
}
|
|
@@ -25076,7 +25590,7 @@ function stage(input) {
|
|
|
25076
25590
|
return input.versions.map((entry2) => {
|
|
25077
25591
|
try {
|
|
25078
25592
|
assertVariantHasNoGraderVerdicts(entry2.variant);
|
|
25079
|
-
return { label: entry2.label, variant: entry2.variant, fingerprint: fingerprint(entry2.variant), dir: writeVariant(PI_SURFACE, entry2.variant,
|
|
25593
|
+
return { label: entry2.label, variant: entry2.variant, fingerprint: fingerprint(entry2.variant), dir: writeVariant(PI_SURFACE, entry2.variant, join73(matrixDir(input.root, input.id), "variants", entry2.label)), error: "" };
|
|
25080
25594
|
} catch (error) {
|
|
25081
25595
|
return { label: entry2.label, variant: entry2.variant, fingerprint: fingerprint(entry2.variant), dir: "", error: error instanceof Error ? error.message : String(error) };
|
|
25082
25596
|
}
|
|
@@ -25103,10 +25617,10 @@ async function runMatrix(input) {
|
|
|
25103
25617
|
};
|
|
25104
25618
|
const save3 = () => {
|
|
25105
25619
|
summary4.usd = Math.round(summary4.rows.reduce((sum, row) => sum + row.costUsd, 0) * 1e6) / 1e6;
|
|
25106
|
-
writeJson(
|
|
25620
|
+
writeJson(join73(matrixDir(root, id), "matrix.json"), summary4);
|
|
25107
25621
|
emit({ type: "summary", summary: structuredClone(summary4) });
|
|
25108
25622
|
};
|
|
25109
|
-
writeJson(
|
|
25623
|
+
writeJson(join73(matrixDir(root, id), "suite.json"), { id, versions: staged.map(({ label, fingerprint: fingerprint2 }) => ({ label, fingerprint: fingerprint2 })), tasks });
|
|
25110
25624
|
save3();
|
|
25111
25625
|
const pairs = staged.flatMap((version2) => tasks.map((task) => ({ version: version2, task })));
|
|
25112
25626
|
await mapLimit(pairs, input.rolloutWidth ?? 4, async ({ version: version2, task }) => {
|
|
@@ -25130,7 +25644,7 @@ async function runMatrix(input) {
|
|
|
25130
25644
|
try {
|
|
25131
25645
|
rollout = await executor.execute(task, version2.dir, runId, runId);
|
|
25132
25646
|
} catch (error) {
|
|
25133
|
-
rollout = { label: runId, runId, dir:
|
|
25647
|
+
rollout = { label: runId, runId, dir: join73(matrixDir(root, id), "missing", version2.label, task.id), ok: false, delivered: false, costUsd: 0, wallMs: 0, error: error instanceof Error ? error.message : String(error) };
|
|
25134
25648
|
}
|
|
25135
25649
|
emit({ type: "execution.finished", version: version2.label, task: task.id, ok: rollout.ok, delivered: rollout.delivered, error: rollout.error });
|
|
25136
25650
|
row = rowOf(version2, task, runId, executorName, rollout);
|
|
@@ -25232,7 +25746,7 @@ async function runRefineCli(argv, io = { write: (text10) => void process.stdout.
|
|
|
25232
25746
|
const { command, values: values2 } = parse3(argv);
|
|
25233
25747
|
try {
|
|
25234
25748
|
if (command === "demo") {
|
|
25235
|
-
const root = values2.out ? resolve14(values2.out) : mkdtempSync10(
|
|
25749
|
+
const root = values2.out ? resolve14(values2.out) : mkdtempSync10(join74(tmpdir11(), "harness-refine-demo-"));
|
|
25236
25750
|
const k = Number(values2.k ?? 1);
|
|
25237
25751
|
seed(root, "demo", demoBaseVariant(), "demo base harness");
|
|
25238
25752
|
const executor = new DemoExecutor(root);
|
|
@@ -25242,7 +25756,7 @@ async function runRefineCli(argv, io = { write: (text10) => void process.stdout.
|
|
|
25242
25756
|
describe3(summary4, io.write);
|
|
25243
25757
|
}
|
|
25244
25758
|
io.write(`library: ${new Library(root, "demo", "accounting").entries().join(", ") || "(empty)"}
|
|
25245
|
-
records: ${
|
|
25759
|
+
records: ${join74(root, "refine")}
|
|
25246
25760
|
`);
|
|
25247
25761
|
return 0;
|
|
25248
25762
|
}
|
|
@@ -25251,13 +25765,13 @@ records: ${join73(root, "refine")}
|
|
|
25251
25765
|
io.write(REFINE_USAGE);
|
|
25252
25766
|
return 2;
|
|
25253
25767
|
}
|
|
25254
|
-
const base =
|
|
25255
|
-
const harness = createHarness({ dataRoot: resolve14(values2.data ??
|
|
25768
|
+
const base = join74(homedir8(), ".xingular-harness");
|
|
25769
|
+
const harness = createHarness({ dataRoot: resolve14(values2.data ?? join74(base, "data")), stateDir: resolve14(values2.state ?? join74(base, "state")) });
|
|
25256
25770
|
try {
|
|
25257
25771
|
const scope = values2.scope ?? basename15(resolve14(values2.variant)).replace(/[^A-Za-z0-9_-]/g, "-");
|
|
25258
25772
|
const variant = readVariant(PI_SURFACE, resolve14(values2.variant));
|
|
25259
25773
|
commit(harness.env.root, scope, variant, { kind: "import", note: `from ${values2.variant}` });
|
|
25260
|
-
const prompt =
|
|
25774
|
+
const prompt = readFileSync34(resolve14(values2.task), "utf8");
|
|
25261
25775
|
const { id } = harness.refine.start({
|
|
25262
25776
|
task: { id: basename15(values2.task).replace(/\.md$/, "").replace(/[^A-Za-z0-9_-]/g, "-"), prompt, scope, sourceDir: values2.source ? resolve14(values2.source) : null },
|
|
25263
25777
|
k: Number(values2.k ?? 1),
|
|
@@ -25283,7 +25797,7 @@ records: ${join73(root, "refine")}
|
|
|
25283
25797
|
}
|
|
25284
25798
|
}
|
|
25285
25799
|
if (command === "matrix") {
|
|
25286
|
-
const root = resolve14(values2.data ??
|
|
25800
|
+
const root = resolve14(values2.data ?? join74(homedir8(), ".xingular-harness", "data"));
|
|
25287
25801
|
let versions2 = [];
|
|
25288
25802
|
let tasks;
|
|
25289
25803
|
if (values2.demo) {
|
|
@@ -25295,7 +25809,7 @@ records: ${join73(root, "refine")}
|
|
|
25295
25809
|
io.write(REFINE_USAGE);
|
|
25296
25810
|
return 2;
|
|
25297
25811
|
}
|
|
25298
|
-
const suite = JSON.parse(
|
|
25812
|
+
const suite = JSON.parse(readFileSync34(resolve14(values2.suite), "utf8"));
|
|
25299
25813
|
if (suite.executor && suite.executor !== "demo") throw new Error(`Executor '${suite.executor}' needs a model; this command runs without one. Use 'demo'.`);
|
|
25300
25814
|
for (const entry2 of suite.versions) {
|
|
25301
25815
|
if (entry2.dir) versions2.push({ label: entry2.label, variant: readVariant(PI_SURFACE, resolve14(entry2.dir)) });
|
|
@@ -25324,7 +25838,7 @@ records: ${join73(root, "refine")}
|
|
|
25324
25838
|
|
|
25325
25839
|
// src/world/cli.ts
|
|
25326
25840
|
import { homedir as homedir9 } from "node:os";
|
|
25327
|
-
import { join as
|
|
25841
|
+
import { join as join75, resolve as resolve15 } from "node:path";
|
|
25328
25842
|
var WEB_USAGE = `Usage: xagent web <status | key <provider> [--remove] | keyless on|off> [--state <dir>] [--data <dir>]
|
|
25329
25843
|
|
|
25330
25844
|
status Which search services are ready
|
|
@@ -25350,8 +25864,8 @@ var BROWSER_USAGE = `Usage: xagent browser [status | set <options>] [--state <di
|
|
|
25350
25864
|
`;
|
|
25351
25865
|
function stateOf2(argv, home) {
|
|
25352
25866
|
const args = [];
|
|
25353
|
-
let stateDir =
|
|
25354
|
-
let dataRoot =
|
|
25867
|
+
let stateDir = join75(home, ".xingular-harness", "state");
|
|
25868
|
+
let dataRoot = join75(home, ".xingular-harness", "data");
|
|
25355
25869
|
for (let index = 0; index < argv.length; index += 1) {
|
|
25356
25870
|
if (argv[index] === "--state") stateDir = resolve15(argv[++index] ?? stateDir);
|
|
25357
25871
|
else if (argv[index] === "--data") dataRoot = resolve15(argv[++index] ?? dataRoot);
|
|
@@ -25369,7 +25883,7 @@ async function readStdin2() {
|
|
|
25369
25883
|
async function runWebCli(argv, dependencies = {}) {
|
|
25370
25884
|
const write4 = dependencies.write ?? ((text10) => void process.stdout.write(text10));
|
|
25371
25885
|
const { args, stateDir, dataRoot } = stateOf2(argv, dependencies.home ?? homedir9());
|
|
25372
|
-
const secrets = dependencies.secrets ?? fileSecretStore(
|
|
25886
|
+
const secrets = dependencies.secrets ?? fileSecretStore(join75(stateDir, "secrets.json"));
|
|
25373
25887
|
const [command, name] = args;
|
|
25374
25888
|
if (!command || command === "help") {
|
|
25375
25889
|
write4(WEB_USAGE);
|
|
@@ -25950,29 +26464,29 @@ function listCommands(plugins) {
|
|
|
25950
26464
|
}
|
|
25951
26465
|
|
|
25952
26466
|
// src/variant/seed.ts
|
|
25953
|
-
import { existsSync as existsSync36, readdirSync as
|
|
25954
|
-
import { join as
|
|
26467
|
+
import { existsSync as existsSync36, readdirSync as readdirSync31, readFileSync as readFileSync35, statSync as statSync23 } from "node:fs";
|
|
26468
|
+
import { join as join76 } from "node:path";
|
|
25955
26469
|
function body(text10) {
|
|
25956
26470
|
return (parse(text10)?.body ?? text10).trim();
|
|
25957
26471
|
}
|
|
25958
26472
|
function read4(path4) {
|
|
25959
26473
|
try {
|
|
25960
|
-
return
|
|
26474
|
+
return readFileSync35(path4, "utf8");
|
|
25961
26475
|
} catch {
|
|
25962
26476
|
return null;
|
|
25963
26477
|
}
|
|
25964
26478
|
}
|
|
25965
26479
|
function folders2(dir2) {
|
|
25966
26480
|
try {
|
|
25967
|
-
return
|
|
26481
|
+
return readdirSync31(dir2).filter((name) => !name.startsWith(".")).sort();
|
|
25968
26482
|
} catch {
|
|
25969
26483
|
return [];
|
|
25970
26484
|
}
|
|
25971
26485
|
}
|
|
25972
26486
|
function blocksDir(root) {
|
|
25973
|
-
if (existsSync36(
|
|
25974
|
-
const moved = folders2(
|
|
25975
|
-
for (const name of moved) if (existsSync36(
|
|
26487
|
+
if (existsSync36(join76(root, "wiki", "blocks"))) return join76(root, "wiki", "blocks");
|
|
26488
|
+
const moved = folders2(join76(root, "legacy")).filter((name) => name.startsWith("wiki-")).reverse();
|
|
26489
|
+
for (const name of moved) if (existsSync36(join76(root, "legacy", name, "blocks"))) return join76(root, "legacy", name, "blocks");
|
|
25976
26490
|
return null;
|
|
25977
26491
|
}
|
|
25978
26492
|
function skillName2(stem) {
|
|
@@ -25983,20 +26497,20 @@ function legacyPieces(root, input) {
|
|
|
25983
26497
|
const scope = { agentId: input.agentId ?? null, projectId: input.projectId ?? null };
|
|
25984
26498
|
const on = (id) => attached(choices, [id], scope, false);
|
|
25985
26499
|
const rules = [];
|
|
25986
|
-
const rulesDir =
|
|
26500
|
+
const rulesDir = join76(root, "registry", "rules");
|
|
25987
26501
|
for (const name of folders2(rulesDir)) {
|
|
25988
26502
|
const stem = name.replace(/\.md$/, "");
|
|
25989
|
-
const path4 = name.endsWith(".md") ?
|
|
26503
|
+
const path4 = name.endsWith(".md") ? join76(rulesDir, name) : join76(rulesDir, name, "SKILL.md");
|
|
25990
26504
|
const text10 = read4(path4);
|
|
25991
26505
|
if (text10 && on(`rules/${stem}`)) rules.push(body(text10));
|
|
25992
26506
|
}
|
|
25993
26507
|
const skills = {};
|
|
25994
|
-
const skillsDir =
|
|
26508
|
+
const skillsDir = join76(root, "registry", "skills");
|
|
25995
26509
|
for (const name of folders2(skillsDir)) {
|
|
25996
26510
|
const stem = name.replace(/\.md$/, "");
|
|
25997
|
-
let path4 =
|
|
26511
|
+
let path4 = join76(skillsDir, name);
|
|
25998
26512
|
try {
|
|
25999
|
-
if (
|
|
26513
|
+
if (statSync23(path4).isDirectory()) path4 = join76(path4, "SKILL.md");
|
|
26000
26514
|
} catch {
|
|
26001
26515
|
continue;
|
|
26002
26516
|
}
|
|
@@ -26015,13 +26529,13 @@ ${body(text10)}
|
|
|
26015
26529
|
const memory = [];
|
|
26016
26530
|
const blocks = blocksDir(root);
|
|
26017
26531
|
if (blocks) {
|
|
26018
|
-
const user = read4(
|
|
26532
|
+
const user = read4(join76(blocks, "shared", "user.md"));
|
|
26019
26533
|
if (user && body(user)) memory.push(`## About the person
|
|
26020
26534
|
|
|
26021
26535
|
${body(user)}`);
|
|
26022
26536
|
if (input.agentId && /^[A-Za-z0-9_-]+$/.test(input.agentId)) {
|
|
26023
26537
|
for (const [file2, title2] of [["persona.md", "Persona"], ["notes.md", "Notes"]]) {
|
|
26024
|
-
const text10 = read4(
|
|
26538
|
+
const text10 = read4(join76(blocks, "agents", input.agentId, file2));
|
|
26025
26539
|
if (text10 && body(text10)) memory.push(`## ${title2}
|
|
26026
26540
|
|
|
26027
26541
|
${body(text10)}`);
|
|
@@ -26219,6 +26733,8 @@ function methods(harness) {
|
|
|
26219
26733
|
return params.render ? { pack, text: render(env, pack) } : pack;
|
|
26220
26734
|
},
|
|
26221
26735
|
"context.runPack": (params) => load2(root(), text7(params, "runId")),
|
|
26736
|
+
// What the request was made of: one row per contributor, reconciled to the provider's figure.
|
|
26737
|
+
"context.attribution": (params) => attribution(env, text7(params, "runId")),
|
|
26222
26738
|
// ---- Plugins: everything that shapes a session, and the trust a working folder's code needs ---
|
|
26223
26739
|
// A host that is not a Node program describes its own parts here instead of in the options.
|
|
26224
26740
|
"plugins.describe": (params) => {
|
|
@@ -26354,12 +26870,12 @@ import { spawn as nodeSpawn } from "node:child_process";
|
|
|
26354
26870
|
import { createHash as createHash17, randomUUID as randomUUID19 } from "node:crypto";
|
|
26355
26871
|
import { appendFileSync as appendFileSync2 } from "node:fs";
|
|
26356
26872
|
import { homedir as homedir11 } from "node:os";
|
|
26357
|
-
import { isAbsolute as isAbsolute13, join as
|
|
26873
|
+
import { isAbsolute as isAbsolute13, join as join78, resolve as resolve16 } from "node:path";
|
|
26358
26874
|
|
|
26359
26875
|
// src/core/interactiveProfile.ts
|
|
26360
|
-
import { closeSync as closeSync7, fsyncSync as fsyncSync3, linkSync as linkSync2, mkdirSync as mkdirSync29, openSync as openSync7, readFileSync as
|
|
26876
|
+
import { closeSync as closeSync7, fsyncSync as fsyncSync3, linkSync as linkSync2, mkdirSync as mkdirSync29, openSync as openSync7, readFileSync as readFileSync36, rmSync as rmSync24, statSync as statSync24, writeFileSync as writeFileSync14 } from "node:fs";
|
|
26361
26877
|
import { homedir as homedir10 } from "node:os";
|
|
26362
|
-
import { dirname as dirname26, isAbsolute as isAbsolute12, join as
|
|
26878
|
+
import { dirname as dirname26, isAbsolute as isAbsolute12, join as join77 } from "node:path";
|
|
26363
26879
|
var fail2 = () => {
|
|
26364
26880
|
throw new Error("Invalid interactive profile configuration.");
|
|
26365
26881
|
};
|
|
@@ -26400,7 +26916,7 @@ function validateInteractiveProfile(value) {
|
|
|
26400
26916
|
};
|
|
26401
26917
|
}
|
|
26402
26918
|
function interactiveProfilePath(home = homedir10()) {
|
|
26403
|
-
return
|
|
26919
|
+
return join77(absolute(home), ".xingular-harness", "profile.json");
|
|
26404
26920
|
}
|
|
26405
26921
|
function selectedConfigPath(location = {}) {
|
|
26406
26922
|
return location.configPath === void 0 ? interactiveProfilePath(location.home) : absolute(location.configPath);
|
|
@@ -26408,9 +26924,9 @@ function selectedConfigPath(location = {}) {
|
|
|
26408
26924
|
function readInteractiveProfile(location = {}) {
|
|
26409
26925
|
const path4 = selectedConfigPath(location);
|
|
26410
26926
|
try {
|
|
26411
|
-
const info =
|
|
26927
|
+
const info = statSync24(path4);
|
|
26412
26928
|
if (!info.isFile() || info.size > 16384) return fail2();
|
|
26413
|
-
return validateInteractiveProfile(JSON.parse(
|
|
26929
|
+
return validateInteractiveProfile(JSON.parse(readFileSync36(path4, "utf8")));
|
|
26414
26930
|
} catch (error) {
|
|
26415
26931
|
if (error.code === "ENOENT") return null;
|
|
26416
26932
|
throw new Error("Interactive profile could not be read or validated.");
|
|
@@ -26424,16 +26940,16 @@ function overrides(value) {
|
|
|
26424
26940
|
}
|
|
26425
26941
|
function resolveInteractiveProfile(options2 = {}) {
|
|
26426
26942
|
const home = absolute(options2.home ?? homedir10());
|
|
26427
|
-
const root =
|
|
26943
|
+
const root = join77(home, ".xingular-harness");
|
|
26428
26944
|
const selected = readInteractiveProfile(options2);
|
|
26429
26945
|
const legacy = overrides(options2.legacyDefaults);
|
|
26430
26946
|
const explicit = overrides(options2.overrides);
|
|
26431
|
-
const dataRoot = explicit.dataRoot ?? selected?.dataRoot ?? legacy.dataRoot ??
|
|
26432
|
-
const stateDir = explicit.stateDir ?? selected?.stateDir ?? legacy.stateDir ??
|
|
26947
|
+
const dataRoot = explicit.dataRoot ?? selected?.dataRoot ?? legacy.dataRoot ?? join77(root, "data");
|
|
26948
|
+
const stateDir = explicit.stateDir ?? selected?.stateDir ?? legacy.stateDir ?? join77(root, "state");
|
|
26433
26949
|
const defaultVariantScope = explicit.defaultVariantScope ?? selected?.defaultVariantScope ?? legacy.defaultVariantScope ?? "default";
|
|
26434
26950
|
const secretBackend = explicit.secretBackend ?? selected?.secretBackend ?? legacy.secretBackend ?? {
|
|
26435
26951
|
kind: "file",
|
|
26436
|
-
path:
|
|
26952
|
+
path: join77(stateDir, "secrets.json")
|
|
26437
26953
|
};
|
|
26438
26954
|
return validateInteractiveProfile({ version: 1, dataRoot, stateDir, defaultVariantScope, secretBackend });
|
|
26439
26955
|
}
|
|
@@ -26487,19 +27003,19 @@ function resolveStandaloneOptions(argv, home = homedir11(), cwd = process.cwd())
|
|
|
26487
27003
|
if (!isAbsolute13(home) && !(given.has("--data") && given.has("--state"))) {
|
|
26488
27004
|
throw new Error(`The home folder "${home}" is not an absolute path, so the default data and state folders cannot be placed. Set HOME to your home folder, or pass --data and --state with absolute folders.`);
|
|
26489
27005
|
}
|
|
26490
|
-
const devRoot = isAbsolute13(home) ?
|
|
26491
|
-
const devData = devRoot ?
|
|
26492
|
-
const devState = devRoot ?
|
|
27006
|
+
const devRoot = isAbsolute13(home) ? join78(home, ".xingular-harness-dev") : null;
|
|
27007
|
+
const devData = devRoot ? join78(devRoot, "data") : null;
|
|
27008
|
+
const devState = devRoot ? join78(devRoot, "state") : null;
|
|
26493
27009
|
const development = !!devRoot && (overrides2.dataRoot === devData || overrides2.stateDir === devState);
|
|
26494
27010
|
const resolvedProfile = isAbsolute13(home) ? resolveInteractiveProfile({
|
|
26495
27011
|
home,
|
|
26496
27012
|
...development ? {
|
|
26497
|
-
configPath:
|
|
27013
|
+
configPath: join78(devRoot, "profile.json"),
|
|
26498
27014
|
legacyDefaults: {
|
|
26499
27015
|
dataRoot: devData,
|
|
26500
27016
|
stateDir: devState,
|
|
26501
27017
|
defaultVariantScope: "default",
|
|
26502
|
-
secretBackend: { kind: "file", path:
|
|
27018
|
+
secretBackend: { kind: "file", path: join78(devState, "secrets.json") }
|
|
26503
27019
|
}
|
|
26504
27020
|
} : {},
|
|
26505
27021
|
overrides: overrides2
|
|
@@ -26508,9 +27024,9 @@ function resolveStandaloneOptions(argv, home = homedir11(), cwd = process.cwd())
|
|
|
26508
27024
|
dataRoot: overrides2.dataRoot,
|
|
26509
27025
|
stateDir: overrides2.stateDir,
|
|
26510
27026
|
defaultVariantScope: "default",
|
|
26511
|
-
secretBackend: { kind: "file", path:
|
|
27027
|
+
secretBackend: { kind: "file", path: join78(overrides2.stateDir, "secrets.json") }
|
|
26512
27028
|
};
|
|
26513
|
-
const profile = development ? { ...resolvedProfile, secretBackend: { kind: "file", path:
|
|
27029
|
+
const profile = development ? { ...resolvedProfile, secretBackend: { kind: "file", path: join78(resolvedProfile.stateDir, "secrets.json") } } : resolvedProfile;
|
|
26514
27030
|
return {
|
|
26515
27031
|
profile,
|
|
26516
27032
|
paths: {
|
|
@@ -26597,7 +27113,7 @@ async function runStandaloneTerminal(argv, dependencies = {}) {
|
|
|
26597
27113
|
const harness = makeHarness({ dataRoot: paths2.dataRoot, stateDir: paths2.stateDir, productName: DEFAULT_PRODUCT_NAME, secrets });
|
|
26598
27114
|
const newSessionId = dependencies.createSessionId ?? randomUUID19;
|
|
26599
27115
|
let current2 = { sessionId: newSessionId(), accountId: null, nativeSessionId: null };
|
|
26600
|
-
const logFile =
|
|
27116
|
+
const logFile = join78(paths2.stateDir, "harness.log");
|
|
26601
27117
|
setLogSink((text10) => {
|
|
26602
27118
|
try {
|
|
26603
27119
|
appendFileSync2(logFile, `${(/* @__PURE__ */ new Date()).toISOString()} ${text10}
|
|
@@ -26619,7 +27135,7 @@ async function runStandaloneTerminal(argv, dependencies = {}) {
|
|
|
26619
27135
|
worktreeId = worktree.id;
|
|
26620
27136
|
}
|
|
26621
27137
|
for (; ; ) {
|
|
26622
|
-
const sessionFolder =
|
|
27138
|
+
const sessionFolder = join78(paths2.dataRoot, "sessions", "terminal", createHash17("sha256").update(cwd).digest("hex"));
|
|
26623
27139
|
const launch = await harness.terminals.prepare({ ...current2, cwd, sessionFolder, variant: { scope: variantScope }, ...worktreeId ? { run: { worktreeId } } : {} });
|
|
26624
27140
|
const code = await spawnFrontend(launch, cwd, dependencies.spawn);
|
|
26625
27141
|
const next = harness.terminals.takeRelaunch(current2.sessionId);
|
|
@@ -26643,7 +27159,7 @@ async function runStandaloneTerminal(argv, dependencies = {}) {
|
|
|
26643
27159
|
|
|
26644
27160
|
// src/worktrees/cli.ts
|
|
26645
27161
|
import { homedir as homedir12 } from "node:os";
|
|
26646
|
-
import { join as
|
|
27162
|
+
import { join as join79, resolve as resolve17 } from "node:path";
|
|
26647
27163
|
var WORKTREE_USAGE = `Usage: xagent worktree <command> [--state <dir>]
|
|
26648
27164
|
|
|
26649
27165
|
list Worktrees of the repository you are in
|
|
@@ -26680,7 +27196,7 @@ async function runWorktreeCli(argv, dependencies = {}) {
|
|
|
26680
27196
|
const write4 = dependencies.write ?? ((text10) => void process.stdout.write(text10));
|
|
26681
27197
|
const cwd = resolve17(dependencies.cwd ?? process.cwd());
|
|
26682
27198
|
const args = [];
|
|
26683
|
-
let stateDir =
|
|
27199
|
+
let stateDir = join79(dependencies.home ?? homedir12(), ".xingular-harness", "state");
|
|
26684
27200
|
for (let index = 0; index < argv.length; index += 1) {
|
|
26685
27201
|
if (argv[index] === "--state") stateDir = resolve17(argv[++index] ?? stateDir);
|
|
26686
27202
|
else args.push(argv[index]);
|