@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.
Files changed (76) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/README.md +1 -1
  3. package/dist/cli.js +1217 -701
  4. package/dist/sdk/computer/screenshot.d.ts +32 -0
  5. package/dist/sdk/computer/screenshot.js +35 -0
  6. package/dist/sdk/context/attribution.d.ts +18 -0
  7. package/dist/sdk/context/attribution.js +295 -0
  8. package/dist/sdk/context/types.d.ts +94 -0
  9. package/dist/sdk/context/types.js +10 -0
  10. package/dist/sdk/index.d.ts +2 -1
  11. package/dist/sdk/index.js +2 -1
  12. package/dist/sdk/plugins/builtin.js +1 -0
  13. package/dist/sdk/prompt/compile.d.ts +42 -2
  14. package/dist/sdk/prompt/compile.js +87 -15
  15. package/dist/sdk/server/methods.js +3 -0
  16. package/dist/sdk/sessions/contracts.d.ts +4 -0
  17. package/dist/sdk/sessions/contracts.js +2 -0
  18. package/dist/sdk/sessions/runner.d.ts +10 -0
  19. package/dist/sdk/sessions/runner.js +17 -0
  20. package/dist/sdk/sessions/subagentService.d.ts +11 -1
  21. package/dist/sdk/sessions/subagentService.js +120 -38
  22. package/dist/sdk/sessions/subagents.d.ts +31 -0
  23. package/dist/sdk/sessions/subagents.js +45 -0
  24. package/dist/sdk/terminal/client.d.ts +1 -1
  25. package/dist/sdk/terminal/client.js +13 -6
  26. package/dist/sdk/terminal/control.d.ts +1 -1
  27. package/dist/sdk/terminal/control.js +2 -2
  28. package/dist/sdk/terminal/controller.d.ts +9 -0
  29. package/dist/sdk/terminal/controller.js +48 -11
  30. package/dist/sdk/terminal/piExtension.js +35 -1
  31. package/dist/sdk/terminal/terminals.d.ts +2 -0
  32. package/dist/sdk/terminal/terminals.js +11 -0
  33. package/dist/sdk/terminal/tui/commands.d.ts +1 -2
  34. package/dist/sdk/terminal/tui/commands.js +1 -4
  35. package/dist/sdk/terminal/tui/dialogs.d.ts +3 -2
  36. package/dist/sdk/terminal/tui/dialogs.js +4 -3
  37. package/dist/sdk/terminal/tui/keybindings.d.ts +1 -1
  38. package/dist/sdk/terminal/tui/keybindings.js +1 -1
  39. package/dist/sdk/terminal/tui/modeChoices.d.ts +3 -2
  40. package/dist/sdk/terminal/tui/modeChoices.js +4 -4
  41. package/dist/sdk/terminal/tui/mouseReport.d.ts +30 -0
  42. package/dist/sdk/terminal/tui/mouseReport.js +80 -0
  43. package/dist/sdk/terminal/tui/pages/annotatePage.js +3 -2
  44. package/dist/sdk/terminal/tui/pages/browserPage.d.ts +1 -1
  45. package/dist/sdk/terminal/tui/pages/contextPage.d.ts +54 -0
  46. package/dist/sdk/terminal/tui/pages/contextPage.js +393 -0
  47. package/dist/sdk/terminal/tui/pages/trajectoryPage.js +5 -4
  48. package/dist/sdk/terminal/tui/runtime.js +8 -2
  49. package/dist/sdk/terminal/tui/search.js +3 -2
  50. package/dist/sdk/terminal/tui/skillInvocation.d.ts +21 -2
  51. package/dist/sdk/terminal/tui/skillInvocation.js +31 -11
  52. package/dist/sdk/tools/defaultSkills.d.ts +19 -0
  53. package/dist/sdk/tools/defaultSkills.js +27 -1
  54. package/dist/sdk/tools/dispatch.js +8 -9
  55. package/dist/sdk/tools/spawnSubagent.d.ts +1 -1
  56. package/dist/sdk/tools/spawnSubagent.js +4 -2
  57. package/dist/terminal-opentui.js +570 -240
  58. package/dist/terminal-pi.js +142 -28
  59. package/docs/README.md +1 -0
  60. package/docs/architecture/02-sessions-and-runs.md +9 -0
  61. package/docs/architecture/04-prompt.md +13 -4
  62. package/docs/architecture/07-tools-and-gate.md +1 -1
  63. package/docs/architecture/11-terminal.md +12 -2
  64. package/docs/architecture/13-world-tools.md +17 -3
  65. package/docs/architecture/14-surfaces-and-parity.md +3 -3
  66. package/docs/architecture/README.md +1 -0
  67. package/docs/architecture/proposals/PROP-0049-context-attribution.md +382 -0
  68. package/docs/architecture/proposals/README.md +1 -0
  69. package/docs/decisions/ADR-0048-required-skills-from-a-message.md +42 -0
  70. package/docs/decisions/ADR-0050-approved-window-screenshots.md +19 -0
  71. package/docs/decisions/ADR-0051-terminal-decision-wait.md +10 -0
  72. package/docs/decisions/ADR-0052-per-profile-subagent-budgets.md +25 -0
  73. package/docs/parity.md +6 -6
  74. package/docs/releases/1.3.1-unstable.3.md +54 -0
  75. package/docs/terminal-tui.md +28 -15
  76. 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 readFileSync26, statSync as statSync15 } from "node:fs";
149
- import { dirname as dirname17, join as join54 } from "node:path";
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 = join54(checkout, SETUP_SCRIPT);
155
- if (!existsSync25(path4) || !statSync15(path4).isFile()) return null;
156
- return { path: path4, hash: scriptHash(readFileSync26(path4)) };
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.2",
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 join14 } from "node:path";
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, limit) {
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, limit)) {
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 readdirSync7, readFileSync as readFileSync8, realpathSync } from "node:fs";
1953
- import { isAbsolute as isAbsolute2, join as join10, relative as relative3 } from "node:path";
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 readdirSync6, readFileSync as readFileSync7, statSync as statSync5 } from "node:fs";
1957
- import { join as join9 } from "node:path";
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 existsSync6, mkdirSync as mkdirSync4, readdirSync as readdirSync5, readFileSync as readFileSync6, renameSync as renameSync2, rmSync as rmSync4, statSync as statSync4 } from "node:fs";
2032
- import { dirname as dirname4, join as join8, relative as relative2, sep as sep3 } from "node:path";
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 join8(root, "wiki");
2111
+ return join9(root, "wiki");
2064
2112
  }
2065
2113
  function historyDir(root) {
2066
- return join8(root, "wiki-history");
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 join8(wikiDir(root), `${cleanPath(path4)}.md`);
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 = readdirSync5(dir2);
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 = join8(dir2, name);
2157
+ const path4 = join9(dir2, name);
2110
2158
  let isDir2 = false;
2111
2159
  try {
2112
- isDir2 = statSync4(path4).isDirectory();
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 (existsSync6(join8(wiki2, "home.md"))) files3.push(join8(wiki2, "home.md"));
2124
- walk2(join8(wiki2, "library"), files3);
2125
- walk2(join8(wiki2, "projects"), files3);
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 = readFileSync6(file2, "utf8");
2131
- return { path: path4, title: titleOf(path4, text10), project: projectOfPath(path4), updatedAt: statSync4(file2).mtime.toISOString(), size: text10.length };
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 = readFileSync6(fileOf(root, node.path), "utf8");
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 (!existsSync6(file2)) throw notFound(`The note ${clean2}`);
2184
- const text10 = readFileSync6(file2, "utf8");
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 (existsSync6(file2)) {
2204
- const current2 = statSync4(file2).mtime.toISOString();
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 = readFileSync6(file2, "utf8");
2254
+ const previous = readFileSync7(file2, "utf8");
2207
2255
  if (previous === body2) return read(root, clean2);
2208
- atomicWrite(join8(historyDir(root), clean2, `${now().replace(/[:.]/g, "-")}.md`), previous);
2256
+ atomicWrite(join9(historyDir(root), clean2, `${now().replace(/[:.]/g, "-")}.md`), previous);
2209
2257
  }
2210
- mkdirSync4(dirname4(file2), { recursive: true });
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 (!existsSync6(file2)) throw notFound(`The note ${clean2}`);
2219
- atomicWrite(join8(historyDir(root), clean2, `${now().replace(/[:.]/g, "-")}.md`), readFileSync6(file2, "utf8"));
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 = join8(historyDir(root), cleanPath(path4));
2271
+ const dir2 = join9(historyDir(root), cleanPath(path4));
2224
2272
  try {
2225
- return readdirSync5(dir2).filter((name) => name.endsWith(".md")).sort().reverse().map((name) => ({ id: name.replace(/\.md$/, ""), savedAt: statSync4(join8(dir2, name)).mtime.toISOString() }));
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 = join8(historyDir(root), cleanPath(path4), `${id}.md`);
2233
- if (!existsSync6(file2)) throw notFound("That version");
2234
- return readFileSync6(file2, "utf8");
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 = readFileSync6(fileOf(root, path4), "utf8");
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(join8(wiki2, "library"), { recursive: true });
2268
- mkdirSync4(join8(wiki2, "projects"), { recursive: true });
2269
- if (!existsSync6(join8(wiki2, "home.md"))) atomicWrite(join8(wiki2, "home.md"), `# Home
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(join8(wiki2, "projects", project.slug), { recursive: true });
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) => existsSync6(join8(wiki2, name)));
2278
- const loose = ["index.md", "log.md", "schema.md"].filter((name) => existsSync6(join8(wiki2, 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 = join8(root, "legacy", `wiki-${now().replace(/[:.]/g, "-")}`);
2328
+ const dest = join9(root, "legacy", `wiki-${now().replace(/[:.]/g, "-")}`);
2281
2329
  mkdirSync4(dest, { recursive: true });
2282
- for (const name of [...found, ...loose]) renameSync2(join8(wiki2, name), join8(dest, name));
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, limit) {
2422
- return charCount(text10) <= limit ? text10 : `${takeChars(text10, limit)}\u2026`;
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: launch.hideToolGuidance ? null : tools2(groups, variant?.toolGuidance ?? "", launch.toolsPointer ?? "") },
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 render(env, pack) {
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
- if (entry2.id === "identity") text10 += `
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
- return text10;
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 join9(root, "runs", safeId(runId), "context.json");
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(join9(root, "runs", safeId(pack.runId)))) writeJson(packPath(root, pack.runId), pack);
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 selected references. 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 apply only to the accompanying request. They do not change permissions. Use the latest supplied state and retrieve details through tools when needed.";
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 = readFileSync7(sessionFile2, "utf8");
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 = readdirSync6(sessionDir);
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 = join9(sessionDir, name);
2834
+ const path4 = join10(sessionDir, name);
2730
2835
  try {
2731
- return [{ path: path4, modified: statSync5(path4).mtimeMs }];
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
- let content = "[App context update \u2014 not a user message]\nListed sections replace their previous app snapshots.\n";
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
- content += current2 ? `
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
- pack.delivery = { systemSectionIds: stable.map((entry2) => entry2.id), updatedSectionIds: updated };
2766
- record(env.root, pack);
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
- `, update: updated.length ? { content, snapshot: snapshot2 } : null, pack };
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(join9(sessionDir, "context.json"), pack);
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(join9(sessionDir, "context.json"));
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(readFileSync8(file2, "utf8").split("\n", 1)[0]);
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 = readdirSync7(sessionDir).filter((name) => name.endsWith(".jsonl"));
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, join10(sessionDir, name)) === nativeSessionId) return realpathSync(join10(sessionDir, name));
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 existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync9 } from "node:fs";
2837
- import { join as join13 } from "node:path";
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 join12 } from "node:path";
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 existsSync7, readdirSync as readdirSync8, rmSync as rmSync5 } from "node:fs";
2846
- import { join as join11 } from "node:path";
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 join11(root, "index.sqlite");
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 = existsSync7(path4) && current2 > 0;
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 readdirSync8(join11(root, "runs"));
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(join12(root, "runs", name, "run.json"))));
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, limit) {
3047
- return withIndex(root, (database) => all(database, "SELECT id FROM runs WHERE session_id = ? ORDER BY started_at DESC LIMIT ?", sessionId, limit).map((row) => row.id));
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 join13(root, "runs", safeId(runId));
3197
+ return join14(root, "runs", safeId(runId));
3077
3198
  }
3078
- var recordPath = (root, runId) => join13(runDir(root, runId), "run.json");
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) => join13(runDir(root, runId), "owner.json");
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(join13(runDir(root, parentRunId), "subagents.json"), [...ids2, childRunId]);
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(join13(runDir(root, parentRunId), "subagents.json"));
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(join13(directory, "events.jsonl"), `${JSON.stringify(event)}
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 = readFileSync9(join13(runDir(root, runId), "events.jsonl"), "utf8");
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 (!existsSync8(backup2)) copyFileSync2(path4, backup2);
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
- await until(parent.ready, parent.stopped.signal);
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 sessionId = randomUUID2();
3640
- const child = {
3641
- ...input,
3642
- 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 },
3643
- accountId,
3644
- poolId: null,
3645
- sessionDir: join14(input.sessionDir, "subagents", runId),
3646
- resume: null,
3647
- text: brief,
3648
- images: void 0,
3649
- requiresImageInput: false,
3650
- preamble: null,
3651
- caller: { ...input.caller, runId: void 0, sessionId },
3652
- tools: { allow: tools4, gated: (input.tools.gated ?? []).filter((name) => tools4.includes(name)) },
3653
- capabilities: childCapabilities,
3654
- depth: (input.depth ?? 0) + 1,
3655
- variant,
3656
- launch,
3657
- model,
3658
- effort,
3659
- ...input.plan ? { connections: false, subagents: null } : {}
3660
- };
3661
- const result = await this.launchChild(parent, request2, child);
3662
- return { ...result, ...profile ? { agent: profile.name } : {}, ...narrowed.unavailable.length ? { unavailableTools: narrowed.unavailable } : {} };
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 = join14(input.sessionDir, "subagents", this.firstLink(latest).id);
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 join68 } from "node:path";
4114
+ import { join as join69 } from "node:path";
3887
4115
 
3888
4116
  // src/accounts/accounts.ts
3889
- import { chmodSync as chmodSync3, existsSync as existsSync9, mkdirSync as mkdirSync9, readdirSync as readdirSync10, rmSync as rmSync7 } from "node:fs";
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 join20 } from "node:path";
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 join15 } from "node:path";
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(join15(packageDir, HTTP_DISPATCHER_CHUNK)).href)
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 join16 } from "node:path";
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) => join16(dir2, safeId(accountId), "choices.json");
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 statSync6, symlinkSync, unlinkSync as unlinkSync2, utimesSync } from "node:fs";
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 dirname5, join as join17, resolve as resolve2, sep as sep4 } from "node:path";
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 = join17(accountsDir, ".sidecar", "pi");
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) => join17(accountsDir, accountId, "home");
3994
- var configDir = (accountsDir, account) => join17(homeDir(accountsDir, account.id), "pi");
3995
- var sharedDir = (accountsDir) => join17(accountsDir, "_shared", "pi");
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(join17(shared, name)) })) };
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 = join17(dirname5(path4), `${basename3(path4)}.xagent-backup-${Math.floor(Date.now() / 1e3)}`);
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 } = statSync6(target);
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(join17(accountsDir, account.id));
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, join17(shared, name), join17(dir2, name), isDir2, linker));
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) => join17(homedir() || "/", 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 readdirSync9, readFileSync as readFileSync10, renameSync as renameSync4, rmSync as rmSync6, writeFileSync as writeFileSync2 } from "node:fs";
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 dirname6, join as join18 } from "node:path";
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 = join18(dirname6(path4), `.credential-${randomUUID3()}.tmp`);
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 = join18(dir2, createHash2("sha256").update(key).digest("hex"));
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 = join18(folder2, id);
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 readdirSync9(folder2)) {
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 = join18(folder2, name);
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 = readFileSync10(join18(participant, "ticket"), "utf8");
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(join18(own, "ticket"), String(ticket));
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(dirname6(path4), { recursive: true, mode: 448 });
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 readFileSync11 } from "node:fs";
4294
- import { join as join19 } from "node:path";
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) => join19(dir2, "accounts.json");
4298
- var statePath = (dir2, accountId) => join19(dir2, safeId(accountId), "state.json");
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(join19(dir2, "audit.jsonl"), JSON.stringify({ at: now(), accountId, action, detail: scrub(detail) }));
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, limit = 100) {
4560
+ function readAudit(dir2, accountId, limit2 = 100) {
4333
4561
  let text10 = "";
4334
4562
  try {
4335
- text10 = readFileSync11(join19(dir2, "audit.jsonl"), "utf8");
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(limit, 1e3));
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((limit) => (limit.status === "rejected" || (limit.usedPercent ?? 0) >= 100) && (!limit.resetsAt || inFuture(limit.resetsAt)));
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((limit) => limit.resetsAt), state.lastError?.resetsAt].filter((reset) => Boolean(reset));
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) => join20(dir2, accountId, "terminal-leases");
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(join20(this.dir, ".credential-locks"), key, work2, this.credentialLockOptions);
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: join20(configDir2, "models.json") })).then((created) => {
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: join20(configDir(this.dir, { id: accountId }), "models.json"), refreshOnCreate: false, allowModelNetwork: false, signal });
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(join20(this.dir, safeId(account.id)), { recursive: true, force: true });
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 = join20(configDir(this.dir, account), "auth.json");
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 && existsSync9(path4) ? readAuth(path4) : null;
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 = join20(configDir(this.dir, account), "auth.json");
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 = readdirSync10(folder2);
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(join20(folder2, name), { force: true });
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(join20(folder2, String(process.pid)), JSON.stringify({ pid: process.pid, startedAt: now() }));
5322
+ atomicWrite(join21(folder2, String(process.pid)), JSON.stringify({ pid: process.pid, startedAt: now() }));
5095
5323
  }
5096
5324
  releaseLease(accountId) {
5097
- rmSync7(join20(leaseFolder(this.dir, accountId), String(process.pid)), { force: true });
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 = (limit) => {
5120
- const time = limit.resetsAt ? Date.parse(limit.resetsAt) : Number.NaN;
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((limit) => limit.provider === readout.provider && !expired(limit))).map((limit) => [limit.id, limit])
5354
+ (readout.source === "provider" ? [] : state.limits.filter((limit2) => limit2.provider === readout.provider && !expired(limit2))).map((limit2) => [limit2.id, limit2])
5127
5355
  );
5128
- for (const limit of readout.limits) kept.set(limit.id, limit);
5129
- state.limits = [...state.limits.filter((limit) => limit.provider !== readout.provider), ...kept.values()];
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 limit of limits) state.limits = [...state.limits.filter((existing) => existing.id !== limit.id), limit];
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 readFileSync22, renameSync as renameSync8, rmSync as rmSync17, writeFileSync as writeFileSync8 } from "node:fs";
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 join21 } from "node:path";
5187
- var path2 = (root) => join21(root, "config/plugin-attachments.json");
5188
- var legacyPath = (root) => join21(root, "config/registry-enabled.json");
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 dirname10 } from "node:path";
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 existsSync10, lstatSync as lstatSync3, readdirSync as readdirSync11, readFileSync as readFileSync12 } from "node:fs";
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 join23, sep as sep5 } from "node:path";
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 join22 } from "node:path";
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(join22(packageRoot, file2), null);
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(join22(packageRoot, "package.json"), {});
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 = join23(root, folder2);
5682
+ const dir2 = join24(root, folder2);
5455
5683
  let names2;
5456
5684
  try {
5457
5685
  if (!lstatSync3(dir2).isDirectory()) return [];
5458
- names2 = readdirSync11(dir2).filter((name) => name.endsWith(".md") && !name.startsWith(".")).sort();
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 = join23(dir2, name);
5692
+ const path4 = join24(dir2, name);
5465
5693
  try {
5466
5694
  if (!lstatSync3(path4).isFile()) continue;
5467
- const front = parse(readFileSync12(path4, "utf8"))?.front;
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, join23(process.env.HOME || homedir2(), ".agents")) ? "home" : "shared";
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 || !existsSync10(join23(root, hooks))) continue;
5542
- found.push({ kind: "hook", path: join23(root, hooks), origin: "package", project: false, packageRoot: root, source, enabled: true });
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
- ...[join23(agentDir, "SYSTEM.md"), join23(agentDir, "APPEND_SYSTEM.md"), join23(cwd, ".pi", "SYSTEM.md"), join23(cwd, ".pi", "APPEND_SYSTEM.md")].filter((path4) => existsSync10(path4))
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 readFileSync14, readdirSync as readdirSync12, statSync as statSync7 } from "node:fs";
5560
- import { dirname as dirname8, resolve as resolve4 } from "node:path";
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 readFileSync13 } from "node:fs";
5564
- import { basename as basename5, dirname as dirname7 } from "node:path";
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(dirname7(item.path)) : file2, description: null };
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 = readFileSync13(path4, "utf8");
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(dirname7(path4)) : basename5(path4).replace(/\.md$/, "");
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(readFileSync14(path4)).digest("hex");
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(readFileSync14(path4, "utf8"));
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(dirname8(path4), entry2);
5645
- const skills = pi.loadSkills({ cwd: dirname8(path4), agentDir: dirname8(path4), includeDefaults: false, skillPaths: (result.skillPaths ?? []).map(absolute2) }).skills;
5646
- const scanner = new pi.DefaultResourceLoader({ cwd: dirname8(path4), agentDir: dirname8(path4), settingsManager: pi.SettingsManager.inMemory({}), noExtensions: true, noSkills: true, noThemes: true, noContextFiles: true, noPromptTemplates: true, additionalPromptTemplatePaths: (result.promptPaths ?? []).map(absolute2) });
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 (statSync7(theme).isDirectory()) return readdirSync12(theme).filter((name) => {
5879
+ if (statSync8(theme).isDirectory()) return readdirSync13(theme).filter((name) => {
5652
5880
  if (!name.endsWith(".json")) return false;
5653
5881
  try {
5654
- return statSync7(resolve4(theme, name)).isFile();
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 readdirSync14, rmSync as rmSync8, unlinkSync as unlinkSync3 } from "node:fs";
5679
- import { join as join25 } from "node:path";
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 readdirSync13, readFileSync as readFileSync15 } from "node:fs";
5685
- import { basename as basename6, dirname as dirname9, join as join24, relative as relative4, sep as sep6 } from "node:path";
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 readdirSync13(path4).sort(compareText)) if (!SKIPPED.has(name)) walk3(join24(path4, name), into);
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.") ? dirname9(item.path) : item.path);
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 = readFileSync15(path4);
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 = join24(stateDir, "plugin-trust.json");
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 readdirSync14(directory, { withFileTypes: true }).filter((entry2) => entry2.isDirectory() && !entry2.name.startsWith(".")).map((entry2) => join25(directory, entry2.name)).sort();
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 = join25(options2.stateDir, "plugin-registered.json");
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(join25(input.agentDir, "skills"));
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 = readdirSync14(path4);
5880
- return entries2.length === 1 && entries2[0] === "SKILL.md" && lstatSync5(join25(path4, "SKILL.md")).isSymbolicLink();
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 = readdirSync14(skillsDir);
6116
+ names2 = readdirSync15(skillsDir);
5889
6117
  } catch {
5890
6118
  return;
5891
6119
  }
5892
6120
  for (const name of names2) {
5893
- const path4 = join25(skillsDir, name);
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", dirname10(dirname10(item.path)));
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 readFileSync20 } from "node:fs";
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 join28 } from "node:path";
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 statSync8 } from "node:fs";
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 join26 } from "node:path";
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) => join26(home, 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 statSync8(path4).isFile();
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 = join26(directory, candidateName);
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 existsSync11, readFileSync as readFileSync16, unlinkSync as unlinkSync4 } from "node:fs";
6143
- import { join as join27 } from "node:path";
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) => join27(root, "config/capability-scope-migration.json");
6193
- var attachmentsPath = (root) => join27(root, "config/plugin-attachments.json");
6194
- var connectionPath = (stateDir) => join27(stateDir, "connections.json");
6195
- var connectionsBackupPath = (stateDir) => join27(stateDir, "connections.pre-capability-scope.json");
6196
- var attachmentsBackupPath = (root) => join27(root, "config/plugin-attachments.pre-capability-scope.json");
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 (!existsSync11(source)) return false;
6259
- if (!existsSync11(target)) atomicWrite(target, readFileSync16(source));
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 (!existsSync11(path4)) return;
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 = existsSync11(connectionsFile);
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 = existsSync11(attachmentsPath(root));
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 && existsSync11(attachmentBackup)) atomicWrite(attachmentsPath(root), readFileSync16(attachmentBackup));
6337
- else if (!hadAttachments && existsSync11(attachmentsPath(root))) unlinkSync4(attachmentsPath(root));
6338
- if (connectionBackup && existsSync11(connectionBackup)) atomicWrite(connectionsFile, readFileSync16(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 = join28(stateDir, "connections.json");
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, limit) => value.length <= limit ? value : `${value.slice(0, limit - 1)}\u2026`;
7179
- function handoffRequest(limit, state, checkpointAvailable = true) {
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 (${limit}; step ${state.steps}). ${handoff} Do not call other tools.`, 600);
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, limit) => {
7430
+ const end = (kind, limit2) => {
7203
7431
  state.endedBy = kind;
7204
- state.endedByLimit = limit;
7205
- options2.onEnd?.(kind, limit);
7432
+ state.endedByLimit = limit2;
7433
+ options2.onEnd?.(kind, limit2);
7206
7434
  const canCheckpoint = checkpointAvailable();
7207
- const reason = kind === "stuck" ? stalledNote(limit, canCheckpoint) : kind === "compaction-thrash" ? handoffRequest("three context compactions in one reply", state, canCheckpoint) : handoffRequest(limit, state, canCheckpoint);
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 limit = sliceLimitReached(policy, state);
7296
- if (limit) {
7523
+ const limit2 = sliceLimitReached(policy, state);
7524
+ if (limit2) {
7297
7525
  state.endedBy = "budget";
7298
- state.endedByLimit = limit;
7526
+ state.endedByLimit = limit2;
7299
7527
  state.refusedAt ??= state.steps;
7300
- return handoff ? void 0 : { block: true, reason: handoffRequest(limit, state, canCheckpoint) };
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, limit = 100) {
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 < limit && !seen.has(current2)) {
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, limit) {
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 > limit) return 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, limit) {
7934
+ function mergeResults(lists, limit2) {
7705
7935
  const seen = /* @__PURE__ */ new Set();
7706
7936
  const merged = [];
7707
- for (let round3 = 0; merged.length < limit && lists.some((list7) => round3 < list7.length); round3 += 1) {
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 >= limit) break;
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 join31 } from "node:path";
8145
+ import { join as join32 } from "node:path";
7916
8146
 
7917
8147
  // src/browser/config.ts
7918
8148
  init_fs();
7919
- import { join as join29 } from "node:path";
7920
- var configPath = (stateDir) => join29(stateDir, "browser.json");
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 join30 } from "node:path";
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(join30(tmpdir2(), `harness-browser-${fileName(this.options.key)}-`));
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 = join30(this.options.downloadsDir, `${Date.now()}-${name}`);
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 : join31(options2.stateDir, "browser", "profiles", fileName(owner)),
8646
- downloadsDir: join31(options2.stateDir, "browser", "downloads", fileName(key)),
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(join31(options2.stateDir, "browser", "downloads", fileName(key)), { recursive: true, force: true });
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 existsSync12, lstatSync as lstatSync6, mkdirSync as mkdirSync11, readdirSync as readdirSync15, rmSync as rmSync11 } from "node:fs";
8681
- import { join as join32 } from "node:path";
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 join32(root, "annotations");
9027
+ return join33(root, "annotations");
8798
9028
  }
8799
9029
  function folder(root) {
8800
9030
  const dir2 = notesDir(root);
8801
- if (existsSync12(dir2) && (lstatSync6(dir2).isSymbolicLink() || !lstatSync6(dir2).isDirectory())) throw new HarnessError("invalid_data", "Note storage must be a plain folder.");
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 join32(folder(root), `${safeId(id)}.json`);
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 (!existsSync12(path4)) throw notFound("Note");
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 readdirSync15(folder(root))) {
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 limit = Math.max(1, Math.min(200, Math.floor(filter.limit ?? 50)));
8855
- return { notes: matching.slice(offset, offset + limit), total: matching.length };
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 (readdirSync15(folder(root)).filter((name) => name.endsWith(".json")).length >= MAX_NOTES) {
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 (existsSync12(file(root, id))) {
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 join37 } from "node:path";
10413
+ import { join as join38 } from "node:path";
10184
10414
 
10185
10415
  // src/refine/library.ts
10186
10416
  init_fs();
10187
- import { existsSync as existsSync14, mkdirSync as mkdirSync13, readdirSync as readdirSync17, readFileSync as readFileSync18, rmSync as rmSync13, writeFileSync as writeFileSync4 } from "node:fs";
10188
- import { join as join34 } from "node:path";
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 existsSync13, mkdirSync as mkdirSync12, readdirSync as readdirSync16, readFileSync as readFileSync17, rmSync as rmSync12, statSync as statSync9, writeFileSync as writeFileSync3 } from "node:fs";
10192
- import { dirname as dirname11, extname as extname2, join as join33, relative as relative5, sep as sep7 } from "node:path";
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 = readdirSync16(dir2);
10440
+ names2 = readdirSync17(dir2);
10211
10441
  } catch {
10212
10442
  return out;
10213
10443
  }
10214
10444
  for (const name of names2.sort()) {
10215
- const path4 = join33(dir2, name);
10445
+ const path4 = join34(dir2, name);
10216
10446
  let isDir2 = false;
10217
10447
  try {
10218
- isDir2 = statSync9(path4).isDirectory();
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 || !existsSync13(root)) return;
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 (!existsSync13(root)) return;
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 = readFileSync17(path4, "utf8");
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 = join33(dst, relative5(src, path4));
10279
- mkdirSync12(dirname11(target), { recursive: true });
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 || !existsSync13(src)) return 0;
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 = join33(root, "source", name);
10294
- mkdirSync12(dirname11(target), { recursive: true });
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(join33(root, "source"), task.leakGlobs);
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(join33(dest, "rollouts"), { recursive: true });
10578
+ mkdirSync12(join34(dest, "rollouts"), { recursive: true });
10349
10579
  try {
10350
- writeFileSync3(join33(dest, "rollouts", `${rollout.label}.md`), executor.trajectory(rollout, { obsTrunc }));
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(join33(dest, "rollouts", `${rollout.label}.md`), `(trajectory unavailable: ${message4})`);
10583
+ writeFileSync3(join34(dest, "rollouts", `${rollout.label}.md`), `(trajectory unavailable: ${message4})`);
10354
10584
  failure2 = `${rollout.label}: ${message4}`;
10355
10585
  }
10356
- const dir2 = join33(dest, "deliverables", rollout.label);
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 = join33(dir2, name);
10367
- mkdirSync12(dirname11(target), { recursive: true });
10596
+ const target = join34(dir2, name);
10597
+ mkdirSync12(dirname12(target), { recursive: true });
10368
10598
  writeFileSync3(target, produced[name]);
10369
10599
  }
10370
- writeFileSync3(join33(dir2, "INDEX.md"), names2.length ? `# ${rollout.label} produced ${names2.length} file(s)
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(join33(dest, "task.md"), task.prompt);
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(join33(dest, "decisions"), { recursive: true });
10395
- writeFileSync3(join33(dest, "decisions", `${label}.md`), notes || "No decision notes returned.");
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 && existsSync13(input.variantDir)) {
10637
+ if (input.variantDir && existsSync14(input.variantDir)) {
10408
10638
  assertNoLeakPaths(input.variantDir, task.leakGlobs);
10409
- harnessFiles = copyFolder(input.variantDir, join33(dest, "harness"));
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 = join33(dest, "pool", entry2.label);
10643
+ const dir2 = join34(dest, "pool", entry2.label);
10414
10644
  mkdirSync12(dir2, { recursive: true });
10415
- if (entry2.variantDir && existsSync13(entry2.variantDir)) {
10645
+ if (entry2.variantDir && existsSync14(entry2.variantDir)) {
10416
10646
  assertNoLeakPaths(entry2.variantDir, task.leakGlobs);
10417
- copyFolder(entry2.variantDir, join33(dir2, "harness"));
10418
- const reference = readVariant(PI_SURFACE, join33(dest, "harness"));
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(join33(dir2, "harness.diff"), unifiedDiff(reference, candidate, "current", entry2.label));
10650
+ writeFileSync3(join34(dir2, "harness.diff"), unifiedDiff(reference, candidate, "current", entry2.label));
10421
10651
  }
10422
10652
  if (entry2.rollout) {
10423
10653
  try {
10424
- writeFileSync3(join33(dir2, "rollout.md"), executor.trajectory(entry2.rollout, { obsTrunc }));
10425
- writeFileSync3(join33(dir2, "produced.md"), renderDeliverable(executor, entry2.rollout) || "(nothing produced)");
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(join33(dir2, "rollout.md"), `(unavailable: ${error instanceof Error ? error.message : String(error)})`);
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 && existsSync13(input.libraryDir) && readdirSync16(input.libraryDir).length) {
10663
+ if (input.libraryDir && existsSync14(input.libraryDir) && readdirSync17(input.libraryDir).length) {
10434
10664
  assertNoLeakPaths(input.libraryDir, task.leakGlobs);
10435
- cpSync(input.libraryDir, join33(dest, "library"), { recursive: true });
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 join34(root, "library");
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 join34(libraryRoot(this.root), this.scope, slug(this.area));
10714
+ return join35(libraryRoot(this.root), this.scope, slug(this.area));
10485
10715
  }
10486
10716
  get index() {
10487
- return join34(this.dir, "INDEX.md");
10717
+ return join35(this.dir, "INDEX.md");
10488
10718
  }
10489
10719
  entryDir(task) {
10490
- return join34(this.dir, "variants", slug(task));
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 existsSync14(this.index) && this.entries().length ? this.dir : null;
10724
+ return existsSync15(this.index) && this.entries().length ? this.dir : null;
10495
10725
  }
10496
10726
  entries() {
10497
- const dir2 = join34(this.dir, "variants");
10727
+ const dir2 = join35(this.dir, "variants");
10498
10728
  try {
10499
- return readdirSync17(dir2, { withFileTypes: true }).filter((entry2) => entry2.isDirectory() && existsSync14(join34(dir2, entry2.name, "EXPERIENCE.md"))).map((entry2) => entry2.name).sort();
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, join34(this.entryDir(task), "variant"));
10735
+ return readVariant(this.surface, join35(this.entryDir(task), "variant"));
10506
10736
  }
10507
10737
  experienceText(task) {
10508
10738
  try {
10509
- return readFileSync18(join34(this.entryDir(task), "EXPERIENCE.md"), "utf8");
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 = readFileSync18(join34(this.dir, "variants", name, "EXPERIENCE.md"), "utf8");
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 (existsSync14(dir2)) {
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(join34(dir2, "variant"), { recursive: true, force: true });
10549
- writeVariant(this.surface, variant, join34(dir2, "variant"), { stubs: false });
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(join34(dir2, "EXPERIENCE.md"), lines2.join("\n"));
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(readFileSync18(join34(this.dir, "variants", name, "EXPERIENCE.md"), "utf8"), "cue");
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 readdirSync17(libraryRoot(root), { withFileTypes: true }).filter((entry2) => entry2.isDirectory()).map((entry2) => entry2.name).sort();
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 readdirSync17(join34(libraryRoot(root), safeId(scope)), { withFileTypes: true }).filter((entry2) => entry2.isDirectory()).map((entry2) => entry2.name).sort();
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 existsSync15 } from "node:fs";
10608
- import { join as join35 } from "node:path";
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(join35(ctx.workDir, "context", label), {
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 || !existsSync15(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, join35(folder2.root, "harness"));
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, join35(ctx.workDir, "variants", label));
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: join35(ctx.workDir, "missing", label), ok: false, delivered: false, costUsd: 0, wallMs: 0, error: error instanceof Error ? error.message : String(error) };
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) => join35(ctx.workDir, "variants", 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 join36 } from "node:path";
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(join36(root, "selection.json"), sel);
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 = join36(input.workDir, "selection", `${mode2}${k}`);
11659
+ const root = join37(input.workDir, "selection", `${mode2}${k}`);
11430
11660
  rmSync14(root, { recursive: true, force: true });
11431
- mkdirSync14(join36(root, "candidates"), { recursive: true });
11432
- writeFileSync5(join36(root, "task.md"), task.prompt);
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(join36(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. -->
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 = join36(input.workDir, "selection", `${mode2}${k}`);
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 = join36(input.workDir, "reflection", `${sel.mode}${sel.k}`);
11499
- const variants = join36(input.workDir, "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: join36(variants, sel.chosenLabel),
11507
- pool: Object.entries(input.rollouts).filter(([label]) => !label.startsWith("base")).map(([label, rollout]) => ({ label, variantDir: join36(variants, label), rollout })),
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, join36(root, "base_harness"), { stubs: false });
11512
- writeFileSync5(join36(root, "adoption.json"), `${JSON.stringify({ chosen_label: sel.chosenLabel, candidate_ids: sel.idMap, reason: sel.why }, null, 2)}
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(join36(root, "edits.md"), `${out.edits}
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, join36(input.workDir, "selection", `${sel.mode}${sel.k}`));
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 join37(root, "refine", safeId(id));
11804
+ return join38(root, "refine", safeId(id));
11575
11805
  }
11576
11806
  function readSummary(root, id) {
11577
- return readJson(join37(refineDir(root, id), "summary.json"));
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(join37(workDir, "summary.json"), summary4);
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(join37(workDir, "task.json"), { task, k, mode: mode2 });
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, join37(workDir, "variants", "base"));
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: join37(workDir, "missing", label), ok: false, delivered: false, costUsd: 0, wallMs: 0, error: error instanceof Error ? error.message : String(error) };
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, limit) {
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(limit, 1), SEARCH_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 limit = typeof requested === "number" && Number.isInteger(requested) && requested >= 0 ? requested : SEARCH_DEFAULT;
11887
- const hits = search2(env.root, query, scope, limit + 4 + (context.recallExcludeAgents?.length ? SEARCH_MAX : 0)).filter((hit2) => hit2.runId !== context.runId && !excluded(env, context, hit2.sessionId)).slice(0, Math.min(Math.max(limit, 1), SEARCH_MAX));
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 readdirSync19, readFileSync as readFileSync19 } from "node:fs";
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 limit = boundedInteger(params, "limit", SEARCH_DEFAULT2, 1, SEARCH_MAX2);
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, limit);
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 limit = boundedInteger(params, "limit", READ_DEFAULT, 1, READ_MAX);
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, limit)) {
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 readdirSync18, renameSync as renameSync5, rmSync as rmSync15, rmdirSync as rmdirSync2, writeFileSync as writeFileSync6 } from "node:fs";
12191
- import { dirname as dirname12, join as join38 } from "node:path";
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) => join38(root, "plugin-proposals");
12197
- var pathOf = (root, id) => join38(dir(root), `${safeId(id)}.json`);
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 = readdirSync18(dir(root));
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 = join38(root, "plugins");
12270
- const destination = join38(parent, proposal.name);
12499
+ const parent = join39(root, "plugins");
12500
+ const destination = join39(parent, proposal.name);
12271
12501
  mkdirSync15(parent, { recursive: true });
12272
- const stage2 = join38(parent, `.proposal-${randomUUID5()}`);
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 = join38(stage2, path4);
12278
- mkdirSync15(dirname12(target), { recursive: true });
12507
+ const target = join39(stage2, path4);
12508
+ mkdirSync15(dirname13(target), { recursive: true });
12279
12509
  writeFileSync6(target, content, { flag: "wx" });
12280
12510
  }
12281
- writeFileSync6(join38(stage2, "package.json"), proposal.manifest, { flag: "wx" });
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")) ? readdirSync19(join40(variantDir, "skills"), { withFileTypes: true }).filter((entry2) => entry2.isDirectory() && existsSync17(join40(variantDir, "skills", entry2.name, "SKILL.md"))).map((entry2) => entry2.name).sort() : [];
12384
- const defaults = defaultSkillPaths(variantDir);
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 (!/^[a-z0-9][a-z0-9_-]*$/.test(wanted)) throw invalid("A skill name is lowercase letters, digits, _ or -.");
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
- if (wanted === "plugin-authoring" && defaults.length) return readFileSync19(defaults[0], "utf8");
12392
- const dir2 = join40(variantDir, "skills", wanted);
12393
- const helpers = existsSync17(join40(dir2, "scripts")) ? readdirSync19(join40(dir2, "scripts")) : [];
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(dir2, "scripts")}: ${helpers.join(", ")}.)` : ""}`;
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(readFileSync20(path4, "utf8"));
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 statSync10 } from "node:fs";
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) && statSync10(source).isDirectory())) throw invalid("That folder does not exist.");
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 readdirSync20, readFileSync as readFileSync21, renameSync as renameSync7, rmSync as rmSync16, writeFileSync as writeFileSync7 } from "node:fs";
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 = readFileSync21(file2, "utf8");
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 = readdirSync20(join43(directory, kind));
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 = readFileSync21(item.path, "utf8");
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 = readFileSync21(item.path, "utf8");
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 readdirSync20(join43(folder2, "scripts"))) next[`skills/${name}/scripts/${file2}`] = readFileSync21(join43(folder2, "scripts", file2), "utf8");
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(readFileSync22(path4, "utf8"));
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(readFileSync22(path4)) === receipt.entry.delivery.sha256 ? "installed" : "changed";
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(readFileSync22(path4)) === receipt.entry.delivery.sha256;
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 = readFileSync22(path4, "utf8");
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 limit = Math.max(1, Math.min(Math.floor(options2.limit ?? TOOL_PAGE), 100));
14257
- const page2 = compactTools(matching.slice(offset, offset + limit));
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 readFileSync25, rmSync as rmSync20, writeFileSync as writeFileSync10 } from "node:fs";
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 readFileSync24, rmSync as rmSync19, writeFileSync as writeFileSync9 } from "node:fs";
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 readdirSync21, readFileSync as readFileSync23, rmSync as rmSync18, statSync as statSync11 } from "node:fs";
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 = readdirSync21(dir2);
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 (statSync11(path4).isDirectory()) files2(path4, into, base);
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 = readFileSync23(path4);
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, limit) {
14968
+ function clip4(text10, limit2) {
14757
14969
  const clean2 = text10.replace(/\0/g, "");
14758
- return limit > 0 && clean2.length > limit ? `${clean2.slice(0, limit)}${TRUNC(clean2.length - limit)}` : clean2;
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] = readFileSync24(join47(rollout.dir, "deliverables", name), "utf8");
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 = readFileSync25(join48(wikiDir(root), `${path4}.md`), "utf8");
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 readdirSync22 } from "node:fs";
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 readdirSync22(dir2).sort().reverse()) {
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")) ? readdirSync22(join49(dir2, "rollouts")).sort() : [];
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 readdirSync23, renameSync as renameSync9 } from "node:fs";
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 readdirSync23(path4, { withFileTypes: true }).filter((entry2) => entry2.isDirectory()).map((entry2) => entry2.name);
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 readFileSync29, statSync as statSync18 } from "node:fs";
15661
- import { basename as basename12, delimiter as delimiter2, isAbsolute as isAbsolute8, join as join59 } from "node:path";
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 statSync12 } from "node:fs";
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 statSync12(path4).isFile();
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 readdirSync24, rmSync as rmSync21, statSync as statSync14 } from "node:fs";
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 statSync13 } from "node:fs";
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 (!statSync13(canonicalCwd).isDirectory()) throw invalid("The working directory must be a directory.");
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 (!statSync13(canonicalRoot).isDirectory()) throw invalid("The workspace root must be a directory.");
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) || !statSync13(canonicalRoot).isDirectory()) {
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 (statSync14(candidate).isFile()) return candidate;
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 = readdirSync24(directory, { withFileTypes: true });
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 readFileSync28, unlinkSync as unlinkSync5, writeFileSync as writeFileSync11 } from "node:fs";
16114
- import { dirname as dirname20, join as join58 } from "node:path";
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.clear();
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.pending.set(String(payload2.questionId), { ...payload2, type: "question", requestId: payload2.questionId, runId: event.runId });
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.pending.set(String(payload2.approvalId), { ...payload2, type: "approval", requestId: payload2.approvalId, runId: event.runId });
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.pending.delete(String(event.payload.approvalId));
17230
+ this.deletePending(String(event.payload.approvalId));
16740
17231
  } else if (event.type === "question.answered") {
16741
- this.pending.delete(String(event.payload.questionId));
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.pending.set(key, {
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.pending.delete(key);
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.pending.set(key, { type: "question", requestId: key, ...summary4 ? { summary: summary4 } : {}, ...sketchMode, question: String(data.question ?? ""), options: data.options ?? [], multiSelect: !!data.multiSelect });
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.pending.delete(key));
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.pending.set(key, { type: "approval", requestId: key, target: String(data.target ?? "Action"), action: String(data.action ?? "{}") });
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.pending.delete(key);
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 readdirSync25, rmSync as rmSync22, statSync as statSync16 } from "node:fs";
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 join55 } from "node:path";
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 = join55(stateDir, "run", `harness-${process.pid}-${randomBytes(8).toString("hex")}.sock`);
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 join55(tmpdir7(), `xh-${process.pid}-${randomBytes(8).toString("hex")}.sock`);
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 = readdirSync25(folder2);
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(join55(folder2, name), { force: true });
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 = join55(dirname18(path4), `harness-${process.pid}-${randomBytes(8).toString("hex")}.sock`);
17054
- return Buffer.byteLength(candidate) <= MAX_SOCKET_PATH ? candidate : join55(tmpdir7(), `xh-${process.pid}-${randomBytes(8).toString("hex")}.sock`);
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 = statSync16(dirname18(path4));
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 statSync17 } from "node:fs";
17267
- import { join as join56 } from "node:path";
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 = statSync17(join56(stateDir, "harness.log"));
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 = join56(stateDir, "harness.log");
17284
- const current2 = statSync17(path4);
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 readFileSync27, readdirSync as readdirSync26, realpathSync as realpathSync5 } from "node:fs";
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 join57, relative as relative8, resolve as resolve9 } from "node:path";
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 readFileSync27(fd, "utf8");
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 = join57(pinned.dir, path4);
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 ? join57(root, "registry") : plugin?.path ?? dirname19(item.path));
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 readdirSync26(directory)) {
18007
+ for (const name of readdirSync28(directory)) {
17515
18008
  if (name.startsWith(".")) continue;
17516
- const path4 = join57(directory, name);
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: readFileSync27(path4).toString("base64"), encoding: "base64" });
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, join58(here, "..", ".."), join58(here, "..", "..", "dist"), join58(here, "..", "dist")].find((folder2) => existsSync26(join58(folder2, "terminal-pi.js"))) ?? 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: join58(dist, "cli.js"),
17575
- piExtension: join58(dist, "terminal-pi.js"),
17576
- openTui: join58(dist, "terminal-opentui.js")
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 = join58(this.options.stateDir, "run", "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 = join58(bin, name);
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 = join58(bin, file2.name);
18197
+ const path4 = join59(bin, file2.name);
17705
18198
  let current2 = null;
17706
18199
  try {
17707
- current2 = readFileSync28(path4, "utf8");
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 join58(input.sessionFolder, "pi");
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) => join59(dir2, name));
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 (statSync18(path4).isFile()) return path4;
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((limit) => `${limit.label || limit.id}: ${limit.usedPercent}% used; resets ${limit.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." };
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") readFileSync29(item.path, "utf8");
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 join60 } from "node:path";
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 = join60(options2.stateDir, "plugin-hooks.json");
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 join61 } from "node:path";
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 = join61(stateDir, "approvals.json");
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 join62 } from "node:path";
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 readFileSync30 } from "node:fs";
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 = readFileSync30(historyFile, "utf8");
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 statSync19 } from "node:fs";
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 (!statSync19(canonical2).isDirectory()) throw new Error(`Write scope is not a directory: ${canonical2}`);
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 compaction = event;
20536
- const summary4 = evidenceText(compaction.result);
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(compaction, "reason", "context limit"),
20540
- aborted: compaction.aborted === true,
20541
- ...typeof compaction.willRetry === "boolean" ? { willRetry: compaction.willRetry } : {},
20542
- ...stringField(compaction, "errorMessage") ? { error: stringField(compaction, "errorMessage").slice(0, 1e3) } : {},
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(join62(runDir(root, runId), "caller.json"), caller);
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 join63 } from "node:path";
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, limit, omitted, fromEnd = false) {
21561
- if (text10.length <= limit) return text10;
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, limit - marker.length);
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(join63(tmpdir8(), "xh-side-question-"));
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 join65, resolve as resolve11 } from "node:path";
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 join64 } from "node:path";
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 = join64(from, relative10);
21881
- const target = join64(to, relative10);
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(join64(checkout, relative10));
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 = join64(checkout, INCLUDE_FILE);
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 ?? join65(stateDir, "worktrees");
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 = join65(stateDir, "worktrees.json");
22002
- this.trust = new SetupTrust(join65(stateDir, "worktree-setup-trust.json"));
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 = join65(this.root, this.repoKey(repoRoot));
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(join65(folder2, wanted))) throw new HarnessError("worktree_exists", `A worktree named ${wanted} already exists.`);
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(join65(folder2, name))) return name;
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 = join65(this.root, this.repoKey(repoRoot), name);
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: join65(this.root, "logs", `${record3.id}.setup.log`), trust: this.trust });
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 = join65(tmpdir9(), `xharness-index-${record3.id}-${randomBytes2(4).toString("hex")}`);
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(join65(target, path4)));
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, limit) {
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 ${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(limit, observedAt) {
22892
- return { ...limit, provider: limit.provider, observedAt };
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 = (limit) => {
22906
- limits.set(limit.id, limit);
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 limit = toNumber(headers.get(`${prefix}limit`));
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 (limit === null && remaining === null && !resetsAt) continue;
22914
- const used = limit !== null && remaining !== null ? Math.max(0, limit - remaining) : null;
22915
- const usedPercent = limit !== null && limit > 0 && used !== null ? used / limit * 100 : null;
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 limit = toNumber(bucket.limit);
23502
+ const limit2 = toNumber(bucket.limit);
22989
23503
  const remaining = toNumber(bucket.remaining);
22990
23504
  const resetsAt = toIso(bucket.reset, now2);
22991
- if (limit === null && remaining === null && !resetsAt) continue;
22992
- const used = limit !== null && remaining !== null ? Math.max(0, limit - remaining) : null;
22993
- const usedPercent = limit !== null && limit > 0 && used !== null ? used / limit * 100 : null;
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, limit) => ({ ...limit, provider, observedAt, source: "provider" });
23031
- var percent = (used, limit) => limit > 0 ? Math.min(100, Math.max(0, used / limit * 100)) : null;
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 limit = typeof data.limit === "number" ? data.limit : null;
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 (limit !== null && remaining !== null) {
23047
- const used = Math.max(0, limit - remaining);
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, limit),
23057
- remainingPercent: percent(remaining, limit),
23058
- status: remaining <= 0 ? "rejected" : percent(used, limit) >= 80 ? "warning" : "allowed"
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 limit of account.state.limits) {
23431
- const provider = limit.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: limit.source === "provider" ? "provider" : "headers", reason: null, observedAt: limit.observedAt ?? this.now().toISOString() });
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((limit) => limit.provider === provider && !(limit.resetsAt && Date.parse(limit.resetsAt) <= this.now().getTime()))
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((limit) => ({ ...limit, provider, observedAt, source: "provider" })),
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((limit) => limit.provider === provider) ?? [];
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 readdirSync27, statSync as statSync20 } from "node:fs";
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 join67 } from "node:path";
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 join66 } from "node:path";
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 join66(this.options.stateDir, "notes-bridge.json");
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 = join67(path4, "Contents", "MacOS");
24362
+ const folder2 = join68(path4, "Contents", "MacOS");
23849
24363
  if (!existsSync32(folder2)) throw new Error(`${path4} has no Contents/MacOS folder.`);
23850
- const programs = readdirSync27(folder2).filter((name) => !name.startsWith(".") && statSync20(join67(folder2, name)).isFile());
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 join67(folder2, program);
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: join67(this.options.stateDir, "browser", "profiles", "person"),
23987
- downloadsDir: join67(this.options.stateDir, "browser", "downloads", fileName(`notes-${key}`)),
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(join68(this.stateDir, "accounts"));
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(join68(this.stateDir, "secrets.json"));
24431
- this.accounts = new Accounts({ dir: join68(this.stateDir, "accounts"), secrets, bus: this.bus });
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 ? join68(this.env.dataRoot, "plugins") : null });
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(join68(this.stateDir, "accounts"));
24455
- const named2 = readJsonOr(join68(shared, "settings.json"), {}).packages;
24456
- if (!packageFolders(join68(this.env.dataRoot, "plugins")).length && !(Array.isArray(named2) && named2.length)) return [];
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(join68(root, folder2), { recursive: true });
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(join68(root, "variants"), { recursive: true });
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 join69, resolve as resolve12 } from "node:path";
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 = join69(dependencies.home ?? homedir6(), ".xingular-harness");
24714
- const options2 = { dataRoot: parsed.values.data ? resolve12(base, parsed.values.data) : join69(root, "data"), stateDir: parsed.values.state ? resolve12(base, parsed.values.state) : join69(root, "state"), productName: DEFAULT_PRODUCT_NAME };
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 join70, resolve as resolve13 } from "node:path";
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 = join70(dependencies.home ?? homedir7(), ".xingular-harness");
24870
- const options2 = { dataRoot: values2.data ?? join70(root, "data"), stateDir: values2.state ?? join70(root, "state") };
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 readFileSync33 } from "node:fs";
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 join73, resolve as resolve14 } from "node:path";
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 readdirSync28, readFileSync as readFileSync31, writeFileSync as writeFileSync12 } from "node:fs";
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 join71 } from "node:path";
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 = join71(root, "sources", id);
25459
+ const sourceDir = join72(root, "sources", id);
24946
25460
  mkdirSync27(sourceDir, { recursive: true });
24947
- writeFileSync12(join71(sourceDir, "ledger.csv"), `amount
25461
+ writeFileSync12(join72(sourceDir, "ledger.csv"), `amount
24948
25462
  ${amounts}`);
24949
- writeFileSync12(join71(sourceDir, "reference_answer.txt"), "never shown to a model");
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 = join71(this.root, "executions", runId);
25483
+ const dir2 = join72(this.root, "executions", runId);
24970
25484
  mkdirSync27(dir2, { recursive: true });
24971
- const script = join71(variantDir ?? "", "scripts", "summarize.mjs");
24972
- const result = spawnSync3(process.execPath, [script, join71(task.sourceDir ?? "", "ledger.csv")], { encoding: "utf8", timeout: 1e4 });
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(join71(dir2, "answer.txt"), result.stdout);
24977
- writeFileSync12(join71(dir2, "trajectory.md"), `[ACTION] Run scripts/summarize.mjs on ledger.csv
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 readFileSync31(join71(rollout.dir, "trajectory.md"), "utf8");
25497
+ return readFileSync32(join72(rollout.dir, "trajectory.md"), "utf8");
24984
25498
  }
24985
25499
  deliverableFiles(rollout) {
24986
- const path4 = join71(rollout.dir, "answer.txt");
24987
- return existsSync33(path4) ? { "answer.txt": readFileSync31(path4, "utf8") } : {};
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(readFileSync31(join71(context, "source", "ledger.csv"), "utf8"))}`;
25006
- const ids2 = readdirSync28(join71(context, "candidates")).filter((name) => name.endsWith(".md")).sort();
25007
- const chosen = ids2.find((name) => readFileSync31(join71(context, "candidates", name), "utf8").includes(expected))?.replace(/\.md$/, "") ?? ids2[0].replace(/\.md$/, "");
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 = readFileSync31(join71(context, "harness", "scripts", "summarize.mjs"), "utf8") !== readFileSync31(join71(context, "base_harness", "scripts", "summarize.mjs"), "utf8");
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(join71(tmpdir10(), "harness-demo-"));
25025
- cpSync5(join71(context, "harness"), workspace, { recursive: true });
25026
- const script = join71(workspace, "scripts", "summarize.mjs");
25027
- writeFileSync12(script, readFileSync31(script, "utf8").replace(".filter((amount) => amount > 0)", ""));
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 readFileSync32 } from "node:fs";
25038
- import { dirname as dirname24, join as join72 } from "node:path";
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 join72(root, "refine", safeId(id));
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 = join72(dir2, "package.json");
25565
+ const manifest = join73(dir2, "package.json");
25052
25566
  if (existsSync34(manifest)) {
25053
- const json2 = JSON.parse(readFileSync32(manifest, "utf8"));
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, join72(matrixDir(input.root, input.id), "variants", entry2.label)), error: "" };
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(join72(matrixDir(root, id), "matrix.json"), summary4);
25620
+ writeJson(join73(matrixDir(root, id), "matrix.json"), summary4);
25107
25621
  emit({ type: "summary", summary: structuredClone(summary4) });
25108
25622
  };
25109
- writeJson(join72(matrixDir(root, id), "suite.json"), { id, versions: staged.map(({ label, fingerprint: fingerprint2 }) => ({ label, fingerprint: fingerprint2 })), tasks });
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: join72(matrixDir(root, id), "missing", version2.label, task.id), ok: false, delivered: false, costUsd: 0, wallMs: 0, error: error instanceof Error ? error.message : String(error) };
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(join73(tmpdir11(), "harness-refine-demo-"));
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: ${join73(root, "refine")}
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 = join73(homedir8(), ".xingular-harness");
25255
- const harness = createHarness({ dataRoot: resolve14(values2.data ?? join73(base, "data")), stateDir: resolve14(values2.state ?? join73(base, "state")) });
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 = readFileSync33(resolve14(values2.task), "utf8");
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 ?? join73(homedir8(), ".xingular-harness", "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(readFileSync33(resolve14(values2.suite), "utf8"));
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 join74, resolve as resolve15 } from "node:path";
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 = join74(home, ".xingular-harness", "state");
25354
- let dataRoot = join74(home, ".xingular-harness", "data");
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(join74(stateDir, "secrets.json"));
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 readdirSync29, readFileSync as readFileSync34, statSync as statSync21 } from "node:fs";
25954
- import { join as join75 } from "node:path";
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 readFileSync34(path4, "utf8");
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 readdirSync29(dir2).filter((name) => !name.startsWith(".")).sort();
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(join75(root, "wiki", "blocks"))) return join75(root, "wiki", "blocks");
25974
- const moved = folders2(join75(root, "legacy")).filter((name) => name.startsWith("wiki-")).reverse();
25975
- for (const name of moved) if (existsSync36(join75(root, "legacy", name, "blocks"))) return join75(root, "legacy", name, "blocks");
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 = join75(root, "registry", "rules");
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") ? join75(rulesDir, name) : join75(rulesDir, name, "SKILL.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 = join75(root, "registry", "skills");
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 = join75(skillsDir, name);
26511
+ let path4 = join76(skillsDir, name);
25998
26512
  try {
25999
- if (statSync21(path4).isDirectory()) path4 = join75(path4, "SKILL.md");
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(join75(blocks, "shared", "user.md"));
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(join75(blocks, "agents", input.agentId, file2));
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 join77, resolve as resolve16 } from "node:path";
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 readFileSync35, rmSync as rmSync24, statSync as statSync22, writeFileSync as writeFileSync14 } from "node:fs";
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 join76 } from "node:path";
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 join76(absolute(home), ".xingular-harness", "profile.json");
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 = statSync22(path4);
26927
+ const info = statSync24(path4);
26412
26928
  if (!info.isFile() || info.size > 16384) return fail2();
26413
- return validateInteractiveProfile(JSON.parse(readFileSync35(path4, "utf8")));
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 = join76(home, ".xingular-harness");
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 ?? join76(root, "data");
26432
- const stateDir = explicit.stateDir ?? selected?.stateDir ?? legacy.stateDir ?? join76(root, "state");
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: join76(stateDir, "secrets.json")
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) ? join77(home, ".xingular-harness-dev") : null;
26491
- const devData = devRoot ? join77(devRoot, "data") : null;
26492
- const devState = devRoot ? join77(devRoot, "state") : null;
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: join77(devRoot, "profile.json"),
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: join77(devState, "secrets.json") }
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: join77(overrides2.stateDir, "secrets.json") }
27027
+ secretBackend: { kind: "file", path: join78(overrides2.stateDir, "secrets.json") }
26512
27028
  };
26513
- const profile = development ? { ...resolvedProfile, secretBackend: { kind: "file", path: join77(resolvedProfile.stateDir, "secrets.json") } } : resolvedProfile;
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 = join77(paths2.stateDir, "harness.log");
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 = join77(paths2.dataRoot, "sessions", "terminal", createHash17("sha256").update(cwd).digest("hex"));
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 join78, resolve as resolve17 } from "node:path";
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 = join78(dependencies.home ?? homedir12(), ".xingular-harness", "state");
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]);