pagegraph 0.14.1 → 0.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +169 -10
  2. package/dist/audit.d.ts +1 -1
  3. package/dist/audit.js +1 -1
  4. package/dist/{checks-BS-aDXB_.js → checks-BEhJPNzN.js} +12 -1
  5. package/dist/checks-BEhJPNzN.js.map +1 -0
  6. package/dist/{claims-Bch7Lxlo.d.ts → claims-CCf2_Jox.d.ts} +2 -2
  7. package/dist/{claims-Bv7voeEV.js → claims-CQlzze1K.js} +2 -2
  8. package/dist/{claims-Bv7voeEV.js.map → claims-CQlzze1K.js.map} +1 -1
  9. package/dist/claims.d.ts +2 -2
  10. package/dist/claims.js +1 -1
  11. package/dist/cli.js +1355 -616
  12. package/dist/cli.js.map +1 -1
  13. package/dist/config.d.ts +7 -3
  14. package/dist/config.js +1 -1
  15. package/dist/config.js.map +1 -1
  16. package/dist/{content-CHd0X4s6.js → content-D5jZprMq.js} +2 -2
  17. package/dist/{content-CHd0X4s6.js.map → content-D5jZprMq.js.map} +1 -1
  18. package/dist/{content-DgNr7apS.d.ts → content-DerWgQy9.d.ts} +11 -3
  19. package/dist/{dist-cFoAzruL.js → dist-Br2oOB2Q.js} +2 -2
  20. package/dist/{dist-cFoAzruL.js.map → dist-Br2oOB2Q.js.map} +1 -1
  21. package/dist/{document-CztEu3Vd.d.ts → document-D9P8yY5g.d.ts} +4 -4
  22. package/dist/{graph-D1PIndsC.d.ts → graph-ChrvU-6X.d.ts} +27 -4
  23. package/dist/{graph-DMNOLXLu.js → graph-UONEaqIX.js} +43 -5
  24. package/dist/graph-UONEaqIX.js.map +1 -0
  25. package/dist/{index-C5w9ripz.d.ts → index-DzjUmbHY.d.ts} +5 -5
  26. package/dist/index.d.ts +6 -6
  27. package/dist/index.js +5 -6
  28. package/dist/index.js.map +1 -1
  29. package/dist/{page-heads-BfjWQvau.d.ts → page-heads-DDz_2_hq.d.ts} +3 -2
  30. package/dist/{page-heads-BgbaIjj9.js → page-heads-YL8nyYjF.js} +4 -3
  31. package/dist/page-heads-YL8nyYjF.js.map +1 -0
  32. package/dist/{pi-D3mMmYey.js → pi-Bz4BgZdC.js} +184 -154
  33. package/dist/pi-Bz4BgZdC.js.map +1 -0
  34. package/dist/{projections-Bk-qOOsR.d.ts → projections-Dqo_ih-J.d.ts} +2 -2
  35. package/dist/react.d.ts +5 -3
  36. package/dist/react.js +43 -19
  37. package/dist/react.js.map +1 -1
  38. package/dist/{state-BuJP_3Lr.js → state-2ikjo7uI.js} +638 -25
  39. package/dist/state-2ikjo7uI.js.map +1 -0
  40. package/dist/tanstack-start/index.d.ts +1 -1
  41. package/dist/tanstack-start/index.js +14 -5
  42. package/dist/tanstack-start/index.js.map +1 -1
  43. package/dist/tanstack-start/react.d.ts +1 -1
  44. package/dist/tanstack-start/server.d.ts +2 -2
  45. package/dist/tanstack-start/server.js +1 -1
  46. package/dist/tanstack-start/server.js.map +1 -1
  47. package/dist/{vite-graph-loader-DZCwejuJ.d.ts → vite-graph-loader-BtLgkN0V.d.ts} +7 -5
  48. package/package.json +1 -1
  49. package/dist/checks-BS-aDXB_.js.map +0 -1
  50. package/dist/declare-D5o7hwmv.js +0 -9
  51. package/dist/declare-D5o7hwmv.js.map +0 -1
  52. package/dist/graph-DMNOLXLu.js.map +0 -1
  53. package/dist/page-heads-BgbaIjj9.js.map +0 -1
  54. package/dist/pi-D3mMmYey.js.map +0 -1
  55. package/dist/state-BuJP_3Lr.js.map +0 -1
@@ -1,10 +1,10 @@
1
1
  import { n as __exportAll$1 } from "./rolldown-runtime-B-lAHAz2.js";
2
- import { $ as decodeUnknownEffect, A as Defect, Bi as none, Bn as runPromise, C as ConfigProvider, E as Boolean, Fn as provideService, Fr as findErrorOption, G as String$1, H as Number$1, Hn as runSync, K as Struct, L as Literal, Li as isSome, Lr as pretty, Nn as provide$1, Or as isSuccess, Q as Unknown, R as Literals, S as option, T as ArraySchema, Tn as mapError, U as Record, V as NullOr, Vi as some, Vn as runPromiseExit, Z as Union, _ as prependUrl, _t as make$1, a as layer$1, b as String$2, c as mapRequest, dn as fn, er as timeoutOption, fr as provide, g as post, gn as gen, h as get, i as normalizeResearchState, jn as orElseSucceed, l as retryTransient, ln as fail, lr as effect, m as bodyJsonUnsafe, n as decodeActionState, ni as format, o as HttpClient, oi as minutes, ot as optional, pn as forEach, q as TaggedError, qn as succeed, r as decodeResearchState, rn as catch_, si as seconds, sr as withSpan, t as actionStateJsonSchema, tr as tryPromise, un as flatMap, v as setHeaders, vt as value, w as fromEnv, wn as map, x as all, xi as Service$1, y as Redacted, zi as match } from "./state-BuJP_3Lr.js";
2
+ import { An as fn, B as fromEnv, Bi as Service$1, E as resolveRepositoryReadPath, Ei as seconds, Er as withSpan, F as Redacted, Fn as gen, H as Boolean, I as String$2, It as make$1, K as Defect, L as all, Lt as value, Mn as forEach, On as fail, Or as effect, Qn as provide$1, R as option, S as normalizeEditPaths, Sn as catch_, Ti as minutes, Tt as optional, Un as map, V as ArraySchema, Wn as mapError, Xn as orElseSucceed, _ as prependUrl, _t as decodeUnknownEffect, a as layer$1, aa as none, ar as runPromise, at as NullOr, b as applyWorkflowEdits, br as tryPromise, c as mapRequest, dt as TaggedError, ei as findErrorOption, er as provideService, et as Literal, fr as succeed, g as post, gt as Unknown, h as get, ht as Union, i as salvageResearchState, ia as match, jr as provide, kn as flatMap, l as retryTransient, lt as String$1, m as bodyJsonUnsafe, n as dropNulls, na as isSome, ni as pretty, o as HttpClient, oa as some, or as runPromiseExit, ot as Number$1, qr as isSuccess, r as normalizeResearchState, sr as runSync, st as Record, t as decodeResearchState, tt as Literals, ut as Struct, v as setHeaders, x as decodeActionState, xi as format, y as actionStateJsonSchema, yr as timeoutOption, z as ConfigProvider } from "./state-2ikjo7uI.js";
3
3
  import { a as ANTHROPIC_OAUTH_TOKEN_ENV, c as ANTHROPIC_WORKSPACE_ID_ENV, i as ANTHROPIC_IDENTITY_TOKEN_FILE_ENV, l as findEnvKeys, n as ANTHROPIC_AUTH_TOKEN_ENV, o as ANTHROPIC_ORGANIZATION_ID_ENV, r as ANTHROPIC_FEDERATION_RULE_ID_ENV, s as ANTHROPIC_SERVICE_ACCOUNT_ID_ENV, t as ANTHROPIC_API_KEY_ENV, u as getEnvApiKey } from "./env-api-keys-C-OA0yM-.js";
4
4
  import { D as lazyApi, _ as normalizeContext, b as toToolDeclaration, d as getCurrentTools, i as createProvider, l as getCurrentSystemMessage, m as getToolStateChanges, r as createModels, s as createInitialSystemMessage, u as getCurrentSystemPrompt } from "./models-DcT5qOEL.js";
5
- import { $ as Ref$1, A as Literal$1, At as IsNumber$1, B as Intersect, Bt as SomeAll$1, C as Number$2, Ct as IsInteger$1, D as IsLiteralBoolean, Dt as IsMinLength$2, E as IsLiteralBigInt, Et as IsMaxLength$2, F as IsBigInt$2, Ft as IsUndefined$1, G as IsCyclic, H as IsEnum$1, I as IsCodec, It as IsUnsafePropertyKey, J as _Object_, K as Unknown$1, L as Hash, Lt as IsValueLike, M as IsInteger$2, Mt as IsObjectNotArray$1, N as Boolean$1, Nt as IsString$1, O as IsLiteralNumber, Ot as IsMultipleOf$1, P as IsBoolean$2, Pt as IsSymbol$1, Q as IsRef$1, R as hash_exports, Rt as Keys$1, S as IsNumber$2, St as IsGreaterThan$1, T as IsLiteral, Tt as IsLessThan$1, U as Match$1, V as IsIntersect, Vt as guard_exports, W as Unsafe, X as Optional, Y as IsOptional, Z as IsNever, _ as IsUnion, _t as IsConstructor$1, a as With, at as IsSchema$1, b as String$3, bt as IsFunction$1, c as IsUndefined$2, ct as Counted$1, d as RecordKey, dt as Every$1, et as IsFunction$2, f as RecordPattern, ft as EveryAll, g as TemplateLiteralDecode, gt as IsBoolean$1, h as Tuple, ht as IsBigInt$1, i as Instantiate, it as _Array_, j as Integer, jt as IsObject$1, k as IsLiteralString, kt as IsNull$1, l as IsRecord, lt as Entries$2, m as IsTuple, mt as IsArray$1, n as Priority, nt as ArrayOptions, o as IsTemplateLiteral, ot as Clone$1, p as RecordValue, pt as HasPropertyKey$1, q as IsObject$2, r as Evaluate$1, rt as IsArray$2, s as IsVoid, st as Get$3, tt as IsConstructor$2, u as Record$1, ut as EntriesRegExp, v as Union$1, vt as IsDeepEqual$1, w as IsNull$2, wt as IsLessEqualThan$1, x as IsSymbol$2, xt as IsGreaterEqualThan$1, y as IsString$2, yt as IsEqual$1, z as Unreachable, zt as Some$1 } from "./dist-cFoAzruL.js";
6
- import { dirname, isAbsolute, relative, resolve, sep } from "node:path";
7
- import { lstat, mkdir, open, readFile, readdir, realpath, writeFile } from "node:fs/promises";
5
+ import { $ as Ref$1, A as Literal$1, At as IsNumber$1, B as Intersect, Bt as SomeAll$1, C as Number$2, Ct as IsInteger$1, D as IsLiteralBoolean, Dt as IsMinLength$2, E as IsLiteralBigInt, Et as IsMaxLength$2, F as IsBigInt$2, Ft as IsUndefined$1, G as IsCyclic, H as IsEnum$1, I as IsCodec, It as IsUnsafePropertyKey, J as _Object_, K as Unknown$1, L as Hash, Lt as IsValueLike, M as IsInteger$2, Mt as IsObjectNotArray$1, N as Boolean$1, Nt as IsString$1, O as IsLiteralNumber, Ot as IsMultipleOf$1, P as IsBoolean$2, Pt as IsSymbol$1, Q as IsRef$1, R as hash_exports, Rt as Keys$1, S as IsNumber$2, St as IsGreaterThan$1, T as IsLiteral, Tt as IsLessThan$1, U as Match$1, V as IsIntersect, Vt as guard_exports, W as Unsafe, X as Optional, Y as IsOptional, Z as IsNever, _ as IsUnion, _t as IsConstructor$1, a as With, at as IsSchema$1, b as String$3, bt as IsFunction$1, c as IsUndefined$2, ct as Counted$1, d as RecordKey, dt as Every$1, et as IsFunction$2, f as RecordPattern, ft as EveryAll, g as TemplateLiteralDecode, gt as IsBoolean$1, h as Tuple, ht as IsBigInt$1, i as Instantiate, it as _Array_, j as Integer, jt as IsObject$1, k as IsLiteralString, kt as IsNull$1, l as IsRecord, lt as Entries$2, m as IsTuple, mt as IsArray$1, n as Priority, nt as ArrayOptions, o as IsTemplateLiteral, ot as Clone$1, p as RecordValue, pt as HasPropertyKey$1, q as IsObject$2, r as Evaluate$1, rt as IsArray$2, s as IsVoid, st as Get$3, tt as IsConstructor$2, u as Record$1, ut as EntriesRegExp, v as Union$1, vt as IsDeepEqual$1, w as IsNull$2, wt as IsLessEqualThan$1, x as IsSymbol$2, xt as IsGreaterEqualThan$1, y as IsString$2, yt as IsEqual$1, z as Unreachable, zt as Some$1 } from "./dist-Br2oOB2Q.js";
6
+ import { relative, resolve } from "node:path";
7
+ import { mkdir, open, readFile, readdir, realpath, writeFile } from "node:fs/promises";
8
8
  //#region node_modules/typebox/build/guard/emit.mjs
9
9
  const identifierRegExp = /^[\p{ID_Start}_$][\p{ID_Continue}_$\u200C\u200D]*$/u;
10
10
  /** Returns true if this value is a valid JavaScript identifier */
@@ -56321,6 +56321,34 @@ const executorTools = (options) => [{
56321
56321
  }];
56322
56322
  //#endregion
56323
56323
  //#region src/workflows/executor.ts
56324
+ /** Retains complete Executor outcomes even when the model-facing preview is truncated. */
56325
+ const persistExecutorToolResults = (toolset, runDirectory) => {
56326
+ const directory = resolve(runDirectory, "tool-results");
56327
+ let sequence;
56328
+ return {
56329
+ trace: toolset.trace,
56330
+ tools: toolset.tools.map((tool) => tool.name !== "executor_execute" ? tool : {
56331
+ ...tool,
56332
+ execute: async (...args) => {
56333
+ const result = await tool.execute(...args);
56334
+ await mkdir(directory, { recursive: true });
56335
+ if (sequence === void 0) {
56336
+ const entries = await readdir(directory);
56337
+ sequence = Math.max(0, ...entries.flatMap((name) => /^\d+\.json$/.test(name) ? [Number(name.slice(0, -5))] : []));
56338
+ }
56339
+ const path = resolve(directory, `${++sequence}.json`);
56340
+ await writeFile(path, JSON.stringify(result.details ?? null, null, 2) + "\n", { flag: "wx" });
56341
+ return result.content.some((part) => part.type === "text" && /\[truncated \d+ chars\]/.test(part.text)) ? {
56342
+ ...result,
56343
+ content: [...result.content, {
56344
+ type: "text",
56345
+ text: `Full Executor result: ${path}. Use read_file to read it; paginate with offset and maxBytes when needed.`
56346
+ }]
56347
+ } : result;
56348
+ }
56349
+ })
56350
+ };
56351
+ };
56324
56352
  const executionEvidence = (record) => {
56325
56353
  if (record.isError) return void 0;
56326
56354
  const succeeded = (record.toolCalls ?? []).filter((call) => !call.isError).map((call) => call.path);
@@ -56368,74 +56396,15 @@ const repositoryToolNames = /* @__PURE__ */ new Set([
56368
56396
  "list_files",
56369
56397
  "search_text"
56370
56398
  ]);
56371
- const writeToolNames = /* @__PURE__ */ new Set(["write_file", "edit_file"]);
56372
- const missingPath = (cause) => cause instanceof Error && "code" in cause && cause.code === "ENOENT";
56373
- const resolveWritablePath = async (path) => {
56374
- let ancestor = path;
56375
- const suffix = [];
56376
- while (true) try {
56377
- return resolve(await realpath(ancestor), ...suffix);
56378
- } catch (cause) {
56379
- if (!missingPath(cause)) throw cause;
56380
- try {
56381
- if ((await lstat(ancestor)).isSymbolicLink()) throw new Error(`Repository path has a dangling symlink: ${path}`);
56382
- } catch (statCause) {
56383
- if (!missingPath(statCause)) throw statCause;
56384
- }
56385
- const parent = dirname(ancestor);
56386
- if (parent === ancestor) throw cause;
56387
- suffix.unshift(relative(parent, ancestor));
56388
- ancestor = parent;
56389
- }
56390
- };
56391
- const writableRepositoryPath = async (root, path, options) => {
56392
- const projectRoot = await realpath(root);
56393
- const requested = resolve(projectRoot, path);
56394
- if (!insideRoot(projectRoot, requested)) throw new Error(`Repository path escapes project root: ${path}`);
56395
- const resolved = await resolveWritablePath(requested);
56396
- if (!insideRoot(projectRoot, resolved)) throw new Error(`Repository path escapes project root through a symlink: ${path}`);
56397
- if ([requested, resolved].some((target) => relative(projectRoot, target).split(sep).some((part) => part === ".git" || part === "node_modules"))) throw new Error(`Repository write targets a protected directory: ${path}`);
56398
- const forbidden = [
56399
- resolve(projectRoot, ".git"),
56400
- resolve(projectRoot, "node_modules"),
56401
- resolve(projectRoot, options.runsDirectory),
56402
- resolve(projectRoot, options.presetDirectory)
56403
- ];
56404
- for (const directory of forbidden) {
56405
- const actual = await resolveWritablePath(directory);
56406
- if (insideRoot(directory, requested) || insideRoot(actual, resolved)) throw new Error(`Repository write targets a protected directory: ${path}`);
56407
- }
56408
- const existing = await lstat(resolved).catch((error) => {
56409
- if (error instanceof Error && "code" in error && error.code === "ENOENT") return void 0;
56410
- throw error;
56411
- });
56412
- if (existing !== void 0 && existing.nlink > 1) throw new Error(`Repository write targets a hard-linked file: ${path}`);
56413
- return resolved;
56414
- };
56415
- const insideRoot = (root, path) => {
56416
- const pathFromRoot = relative(root, path);
56417
- return pathFromRoot !== ".." && !pathFromRoot.startsWith(`..${sep}`) && !isAbsolute(pathFromRoot);
56418
- };
56419
- const repositoryPath = async (root, path) => {
56420
- const projectRoot = await realpath(root);
56421
- const requested = resolve(projectRoot, path);
56422
- if (!insideRoot(projectRoot, requested) && !insideRoot(resolve(root), requested)) throw new Error(`Repository path escapes project root: ${path}`);
56423
- const resolved = await realpath(requested);
56424
- if (!insideRoot(projectRoot, resolved)) throw new Error(`Repository path escapes project root through a symlink: ${path}`);
56425
- return resolved;
56426
- };
56427
56399
  const pathArgument = (args) => {
56428
56400
  if (typeof args !== "object" || args === null || !("path" in args) || typeof args.path !== "string") throw new Error("Repository tools require a string path");
56429
56401
  return args.path;
56430
56402
  };
56431
- const guardRepositoryToolCall = (root, writeOptions) => async ({ toolCall, args }, signal) => {
56432
- if (!repositoryToolNames.has(toolCall.name) && !writeToolNames.has(toolCall.name)) return void 0;
56403
+ const guardRepositoryToolCall = (root, readOptions) => async ({ toolCall, args }, signal) => {
56404
+ if (!repositoryToolNames.has(toolCall.name)) return void 0;
56433
56405
  try {
56434
56406
  signal?.throwIfAborted();
56435
- if (writeToolNames.has(toolCall.name)) {
56436
- if (!writeOptions) throw new Error("Repository writes are unavailable in this workflow phase");
56437
- await writableRepositoryPath(root, pathArgument(args), writeOptions);
56438
- } else await repositoryPath(root, pathArgument(args));
56407
+ await resolveRepositoryReadPath(readOptions?.repositoryRoot ?? root, pathArgument(args), readOptions);
56439
56408
  return;
56440
56409
  } catch (error) {
56441
56410
  return {
@@ -56444,15 +56413,20 @@ const guardRepositoryToolCall = (root, writeOptions) => async ({ toolCall, args
56444
56413
  };
56445
56414
  }
56446
56415
  };
56447
- const readBoundedFile = async (path, signal) => {
56416
+ const readBoundedFile = async (path, signal, offset = 0, maxBytes = MAX_FILE_BYTES) => {
56448
56417
  signal?.throwIfAborted();
56449
56418
  const file = await open(path, "r");
56450
56419
  try {
56451
56420
  if (!(await file.stat()).isFile()) throw new Error(`Repository path is not a regular file: ${path}`);
56452
- const buffer = Buffer.alloc(65537);
56453
- const { bytesRead } = await file.read(buffer, 0, buffer.length, 0);
56421
+ const buffer = Buffer.alloc(maxBytes + 1);
56422
+ const { bytesRead } = await file.read(buffer, 0, buffer.length, offset);
56454
56423
  signal?.throwIfAborted();
56455
- return buffer.subarray(0, Math.min(bytesRead, MAX_FILE_BYTES)).toString("utf8") + (bytesRead > MAX_FILE_BYTES ? "\n[File truncated at 64 KiB]" : "");
56424
+ let consumed = Math.min(bytesRead, maxBytes);
56425
+ if (bytesRead > maxBytes) {
56426
+ while (consumed > 0 && (buffer[consumed] & 192) === 128) consumed--;
56427
+ if (consumed === 0) throw new Error("read_file maxBytes cannot fit the next UTF-8 character; increase maxBytes");
56428
+ }
56429
+ return buffer.subarray(0, consumed).toString("utf8") + (bytesRead > maxBytes ? `\n[File truncated; continue with read_file offset=${offset + consumed}]` : "");
56456
56430
  } finally {
56457
56431
  await file.close();
56458
56432
  }
@@ -56464,14 +56438,14 @@ const result = (text) => ({
56464
56438
  }],
56465
56439
  details: void 0
56466
56440
  });
56467
- const discoverFiles = async (root, directory, recursive, signal) => {
56441
+ const discoverFiles = async (root, directory, recursive, signal, options) => {
56468
56442
  const files = [];
56469
56443
  const pending = [directory];
56470
56444
  let inspected = 0;
56471
56445
  while (pending.length > 0 && inspected < MAX_ENTRIES) {
56472
56446
  signal?.throwIfAborted();
56473
56447
  const next = pending.shift();
56474
- const entries = (await readdir(await repositoryPath(root, next), { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name));
56448
+ const entries = (await readdir(await resolveRepositoryReadPath(root, next, options), { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name));
56475
56449
  for (const entry of entries) {
56476
56450
  if (++inspected > MAX_ENTRIES) break;
56477
56451
  const path = resolve(next, entry.name);
@@ -56481,13 +56455,26 @@ const discoverFiles = async (root, directory, recursive, signal) => {
56481
56455
  }
56482
56456
  return files;
56483
56457
  };
56484
- const createRepositoryTools = (root) => [
56458
+ const byteArgument = (args, key, fallback, minimum, maximum) => {
56459
+ const value = typeof args === "object" && args !== null ? Reflect.get(args, key) : void 0;
56460
+ if (value === void 0) return fallback;
56461
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < minimum || value > maximum) throw new Error(`read_file ${key} must be an integer between ${minimum} and ${maximum}`);
56462
+ return value;
56463
+ };
56464
+ const createRepositoryTools = (root, options = {}) => [
56485
56465
  {
56486
56466
  name: "read_file",
56487
56467
  label: "Read repository file",
56488
- description: "Read a UTF-8 file within the project root, limited to 64 KiB.",
56489
- parameters: _Object_({ path: String$3() }),
56490
- execute: async (_id, args, signal) => result(await readBoundedFile(await repositoryPath(root, pathArgument(args)), signal))
56468
+ description: "Read a UTF-8 repository or run-artifact file. offset is a byte offset (default 0); maxBytes is at most 65536. A truncated page tells you the next offset.",
56469
+ parameters: _Object_({
56470
+ path: String$3(),
56471
+ offset: Optional(Integer({ minimum: 0 })),
56472
+ maxBytes: Optional(Integer({
56473
+ minimum: 1,
56474
+ maximum: MAX_FILE_BYTES
56475
+ }))
56476
+ }),
56477
+ execute: async (_id, args, signal) => result(await readBoundedFile(await resolveRepositoryReadPath(root, pathArgument(args), options), signal, byteArgument(args, "offset", 0, 0, Number.MAX_SAFE_INTEGER), byteArgument(args, "maxBytes", MAX_FILE_BYTES, 1, MAX_FILE_BYTES)))
56491
56478
  },
56492
56479
  {
56493
56480
  name: "list_files",
@@ -56502,8 +56489,8 @@ const createRepositoryTools = (root) => [
56502
56489
  const recursive = typeof args === "object" && args !== null && "recursive" in args ? args.recursive : false;
56503
56490
  if (typeof recursive !== "boolean") throw new Error("list_files recursive must be a boolean");
56504
56491
  const projectRoot = await realpath(root);
56505
- const directory = await repositoryPath(root, path);
56506
- const files = await discoverFiles(root, directory, recursive, signal);
56492
+ const directory = await resolveRepositoryReadPath(root, path, options);
56493
+ const files = await discoverFiles(root, directory, recursive, signal, options);
56507
56494
  return result(files.map((file) => relative(projectRoot, file)).join("\n").slice(0, MAX_OUTPUT_CHARACTERS));
56508
56495
  }
56509
56496
  },
@@ -56520,11 +56507,11 @@ const createRepositoryTools = (root) => [
56520
56507
  const text = typeof args === "object" && args !== null && "text" in args ? args.text : void 0;
56521
56508
  if (typeof text !== "string" || text.length === 0) throw new Error("search_text requires nonempty literal text");
56522
56509
  const projectRoot = await realpath(root);
56523
- const directory = await repositoryPath(root, path);
56524
- const files = await discoverFiles(root, directory, true, signal);
56510
+ const directory = await resolveRepositoryReadPath(root, path, options);
56511
+ const files = await discoverFiles(root, directory, true, signal, options);
56525
56512
  const matches = [];
56526
56513
  for (const file of files) {
56527
- const content = await readBoundedFile(await repositoryPath(root, file), signal);
56514
+ const content = await readBoundedFile(await resolveRepositoryReadPath(root, file, options), signal);
56528
56515
  if (content.includes("\0")) continue;
56529
56516
  for (const [index, line] of content.split("\n").entries()) {
56530
56517
  if (line.includes(text)) matches.push(`${relative(projectRoot, file)}:${index + 1}:${line}`);
@@ -56536,51 +56523,6 @@ const createRepositoryTools = (root) => [
56536
56523
  }
56537
56524
  }
56538
56525
  ];
56539
- const stringArgument = (args, key) => {
56540
- if (typeof args !== "object" || args === null || !(key in args) || typeof Reflect.get(args, key) !== "string") throw new Error(`Repository tools require a string ${key}`);
56541
- return Reflect.get(args, key);
56542
- };
56543
- const createRepositoryWriteTools = (root, options) => [{
56544
- name: "write_file",
56545
- label: "Write repository file",
56546
- description: "Create or overwrite a UTF-8 repository file. Protected directories and symlink escapes are blocked.",
56547
- parameters: _Object_({
56548
- path: String$3(),
56549
- content: String$3()
56550
- }),
56551
- execute: async (_id, args, signal) => {
56552
- signal?.throwIfAborted();
56553
- const requested = pathArgument(args);
56554
- const path = await writableRepositoryPath(root, requested, options);
56555
- await mkdir(dirname(path), { recursive: true });
56556
- signal?.throwIfAborted();
56557
- await writeFile(await writableRepositoryPath(root, pathArgument(args), options), stringArgument(args, "content"), "utf8");
56558
- return result(`Wrote ${pathArgument(args)}`);
56559
- }
56560
- }, {
56561
- name: "edit_file",
56562
- label: "Edit repository file",
56563
- description: "Replace exact text in a UTF-8 repository file. oldText must match exactly one region; protected directories and symlink escapes are blocked.",
56564
- parameters: _Object_({
56565
- path: String$3(),
56566
- oldText: String$3({ minLength: 1 }),
56567
- newText: String$3()
56568
- }),
56569
- execute: async (_id, args, signal) => {
56570
- signal?.throwIfAborted();
56571
- const oldText = stringArgument(args, "oldText");
56572
- const newText = stringArgument(args, "newText");
56573
- if (oldText.length === 0) throw new Error("edit_file oldText must be nonempty");
56574
- const requested = pathArgument(args);
56575
- const path = await writableRepositoryPath(root, requested, options);
56576
- const content = await readFile(path, "utf8");
56577
- const index = content.indexOf(oldText);
56578
- if (index < 0 || content.indexOf(oldText, index + 1) >= 0) throw new Error("edit_file oldText must match exactly once");
56579
- signal?.throwIfAborted();
56580
- await writeFile(await writableRepositoryPath(root, pathArgument(args), options), content.slice(0, index) + newText + content.slice(index + oldText.length), "utf8");
56581
- return result(`Edited ${pathArgument(args)}`);
56582
- }
56583
- }];
56584
56526
  //#endregion
56585
56527
  //#region src/workflows/pi.ts
56586
56528
  const MAX_REJECTED_SUBMISSIONS = 3;
@@ -56642,36 +56584,97 @@ var WorkflowRunnerError = class extends Error {
56642
56584
  };
56643
56585
  const createPiRunner = (options) => {
56644
56586
  let agent;
56645
- let researched = false;
56646
- const phase = async (spec, prompt, signal, mode) => {
56587
+ let researched = options.resume?.phase === "action";
56588
+ let resume = options.resume;
56589
+ const priorEvidence = options.resume?.executor;
56590
+ const evidence = () => {
56591
+ const current = executorEvidence(options.executor.trace);
56592
+ return priorEvidence === void 0 ? current : {
56593
+ searches: [...priorEvidence.searches, ...current.searches],
56594
+ calls: [...priorEvidence.calls, ...current.calls]
56595
+ };
56596
+ };
56597
+ const replayTools = options.executor.tools.map((tool) => ({
56598
+ ...tool,
56599
+ execute: async (id, params, signal, onUpdate) => {
56600
+ if (priorEvidence !== void 0 && typeof params === "object" && params !== null) {
56601
+ const recorded = tool.name === "executor_execute" && "code" in params ? priorEvidence.calls.findLast((call) => typeof call.input === "object" && call.input !== null && "code" in call.input && call.input.code === params.code) : tool.name === "executor_search" && "query" in params ? priorEvidence.searches.findLast((call) => typeof call.input === "object" && call.input !== null && "query" in call.input && call.input.query === params.query) : void 0;
56602
+ if (recorded !== void 0) {
56603
+ const text = JSON.stringify(recorded.output) ?? "null";
56604
+ return {
56605
+ content: [{
56606
+ type: "text",
56607
+ text: `Recorded completed Executor result (reused without a provider call):\n${text.length > 3e4 ? `${text.slice(0, 3e4)}... [truncated ${text.length - 3e4} chars]` : text}`
56608
+ }],
56609
+ details: recorded.output
56610
+ };
56611
+ }
56612
+ }
56613
+ return tool.execute(id, params, signal, onUpdate);
56614
+ }
56615
+ }));
56616
+ const executor = options.runDirectory === void 0 ? {
56617
+ ...options.executor,
56618
+ tools: replayTools
56619
+ } : persistExecutorToolResults({
56620
+ ...options.executor,
56621
+ tools: replayTools
56622
+ }, options.runDirectory);
56623
+ const writeOptions = {
56624
+ presetDirectory: options.presetDirectory,
56625
+ runsDirectory: options.runsDirectory ?? resolve(options.root, ".pagegraph/runs")
56626
+ };
56627
+ const readOptions = {
56628
+ repositoryRoot: options.repositoryRoot ?? options.root,
56629
+ runsDirectory: options.runsDirectory ?? resolve(options.root, ".pagegraph/runs")
56630
+ };
56631
+ const phase = async (spec, prompt, signal, action = false) => {
56647
56632
  const assertDeadline = (messages = []) => {
56648
56633
  if (signal.aborted) throw new WorkflowRunnerError(`Workflow deadline exceeded or run aborted: ${String(signal.reason)}`, {
56649
56634
  messages,
56650
56635
  usage: totalUsage(messages),
56651
- executor: executorEvidence(options.executor.trace)
56636
+ executor: evidence()
56652
56637
  }, { cause: signal.reason });
56653
56638
  };
56654
56639
  assertDeadline(agent?.state.messages);
56655
- if (mode !== void 0 && !researched) throw new Error("Workflow action requires a completed research conversation");
56656
- const systemPrompt = mode === void 0 ? await composeSystemPrompt(options.presetDirectory, spec) : void 0;
56640
+ if (action && !researched) throw new Error("Workflow action requires a completed research conversation");
56641
+ const systemPrompt = !action || agent === void 0 ? await composeSystemPrompt(options.presetDirectory, spec) : void 0;
56657
56642
  assertDeadline();
56643
+ const validateAction = async (raw) => {
56644
+ const state = normalizeEditPaths(decodeActionState(dropNulls(raw)), readOptions.repositoryRoot, options.root);
56645
+ const refused = (await applyWorkflowEdits(options.root, state.edits.map((edit, index) => ({
56646
+ id: `edits[${index}]`,
56647
+ ...edit
56648
+ })), {
56649
+ ...writeOptions,
56650
+ check: true
56651
+ })).filter((outcome) => outcome.status !== "applicable");
56652
+ if (refused.length > 0) throw new Error(`Edits must apply to the current files:\n${refused.map((outcome) => `${outcome.id} (${outcome.path}): ${outcome.status}, ${outcome.reason}`).join("\n")}\nCopy oldText exactly from a fresh read_file result, with enough context to match once.`);
56653
+ return state;
56654
+ };
56658
56655
  let state;
56659
56656
  let submitted = false;
56660
56657
  let rejected = 0;
56661
56658
  let lastIssues = "No structured result was submitted.";
56659
+ let lastSubmission;
56660
+ let rejectedItems;
56662
56661
  const rawSubmissions = /* @__PURE__ */ new Map();
56663
56662
  const submit = {
56664
56663
  name: "submit_result",
56665
56664
  label: "Submit workflow result",
56666
56665
  description: "Validate and submit the final workflow state after collecting Executor evidence.",
56667
- parameters: Unsafe(mode === void 0 ? spec.stateJsonSchema : actionStateJsonSchema),
56668
- prepareArguments: (args) => mode === void 0 ? normalizeResearchState(args, options.limit) : args,
56666
+ parameters: Unsafe(action ? actionStateJsonSchema : spec.stateJsonSchema),
56667
+ prepareArguments: (args) => {
56668
+ lastSubmission = args;
56669
+ return action ? dropNulls(args) : normalizeResearchState(args, options.limit);
56670
+ },
56669
56671
  execute: async (_id, params) => {
56670
56672
  try {
56671
- const decoded = mode === void 0 ? decodeResearchState(spec, rawSubmissions.get(_id) ?? params, options.limit) : decodeActionState(rawSubmissions.get(_id) ?? params);
56672
- const evidence = executorEvidence(options.executor.trace);
56673
- if (mode === void 0 && (evidence.searches.length === 0 || evidence.calls.length === 0)) throw new Error([
56674
- `Your research returned without completed Executor provider evidence (searches: ${evidence.searches.length}, calls: ${evidence.calls.length}).`,
56673
+ const raw = rawSubmissions.get(_id) ?? lastSubmission ?? params;
56674
+ const decoded = action ? await validateAction(raw) : decodeResearchState(spec, raw, options.limit);
56675
+ const collected = evidence();
56676
+ if (!action && (collected.searches.length === 0 || collected.calls.length === 0)) throw new Error([
56677
+ `Your research returned without completed Executor provider evidence (searches: ${collected.searches.length}, calls: ${collected.calls.length}).`,
56675
56678
  "Catalog searches and schema discovery alone do not satisfy this workflow.",
56676
56679
  "Use the catalog results already collected, inspect the exact discovered tool schema, and complete at least one relevant read-only provider call before submitting the original workflow state.",
56677
56680
  "Preserve provider errors and empty datasets honestly; do not invent evidence or mutate provider state."
@@ -56700,29 +56703,26 @@ const createPiRunner = (options) => {
56700
56703
  }
56701
56704
  }
56702
56705
  };
56703
- const writeOptions = {
56704
- presetDirectory: options.presetDirectory,
56705
- runsDirectory: options.runsDirectory ?? resolve(options.root, ".pagegraph/runs")
56706
- };
56707
56706
  const tools = [
56708
- ...options.executor.tools,
56709
- ...createRepositoryTools(options.root),
56707
+ ...executor.tools,
56708
+ ...createRepositoryTools(readOptions.repositoryRoot, readOptions),
56710
56709
  ...options.additionalTools ?? [],
56711
- ...mode === "write" ? createRepositoryWriteTools(options.root, writeOptions) : [],
56712
56710
  submit
56713
56711
  ];
56714
56712
  if (systemPrompt !== void 0) {
56715
- researched = false;
56713
+ if (!action) researched = false;
56716
56714
  agent = new Agent({
56717
56715
  initialState: {
56718
56716
  systemPrompt,
56719
56717
  model: options.model,
56720
- tools
56718
+ tools,
56719
+ ...resume === void 0 ? {} : { messages: [...resume.agent.messages] }
56721
56720
  },
56722
56721
  streamFn: options.streamFn ?? streamSimple,
56723
56722
  getApiKey: getEnvApiKey,
56724
56723
  toolExecution: "sequential"
56725
56724
  });
56725
+ resume = void 0;
56726
56726
  }
56727
56727
  if (!agent) throw new Error("Workflow action requires a research conversation");
56728
56728
  agent.state.tools = tools;
@@ -56733,7 +56733,7 @@ const createPiRunner = (options) => {
56733
56733
  terminate: true
56734
56734
  };
56735
56735
  if (context.toolCall.name === "submit_result") rawSubmissions.set(context.toolCall.id, context.toolCall.arguments);
56736
- return guardRepositoryToolCall(options.root, mode === "write" ? writeOptions : void 0)?.(context, signal);
56736
+ return guardRepositoryToolCall(options.root, readOptions)?.(context, signal);
56737
56737
  };
56738
56738
  agent.finishTurn = () => submitted || rejected >= MAX_REJECTED_SUBMISSIONS ? { action: "end" } : void 0;
56739
56739
  const current = agent;
@@ -56751,15 +56751,30 @@ const createPiRunner = (options) => {
56751
56751
  const result = {
56752
56752
  messages: current.state.messages,
56753
56753
  usage: totalUsage(current.state.messages),
56754
- executor: executorEvidence(options.executor.trace)
56754
+ executor: evidence()
56755
56755
  };
56756
56756
  if (signal.aborted) throw new WorkflowRunnerError(`Workflow deadline exceeded or run aborted: ${String(signal.reason)}`, result, { cause: signal.reason });
56757
+ if (!submitted && !action && rejected >= MAX_REJECTED_SUBMISSIONS && result.executor.searches.length > 0 && result.executor.calls.length > 0) try {
56758
+ const salvaged = salvageResearchState(spec, lastSubmission, options.limit);
56759
+ state = salvaged.state;
56760
+ rejectedItems = salvaged.rejectedItems;
56761
+ submitted = true;
56762
+ } catch {}
56757
56763
  if (!submitted) throw new WorkflowRunnerError(`Workflow result rejected: ${lastIssues}${current.state.errorMessage ? `\n${current.state.errorMessage}` : ""}`, result);
56758
- if (mode === void 0) researched = true;
56764
+ if (!action) researched = true;
56759
56765
  return {
56760
56766
  ...result,
56761
- state
56767
+ state,
56768
+ ...rejectedItems === void 0 ? {} : { rejectedItems }
56762
56769
  };
56770
+ } catch (cause) {
56771
+ if (cause instanceof WorkflowRunnerError) throw cause;
56772
+ const messages = current.state.messages;
56773
+ throw new WorkflowRunnerError(`Workflow agent turn failed: ${cause instanceof Error ? cause.message : String(cause)}`, {
56774
+ messages,
56775
+ usage: totalUsage(messages),
56776
+ executor: evidence()
56777
+ }, { cause });
56763
56778
  } finally {
56764
56779
  signal.removeEventListener("abort", abort);
56765
56780
  unsubscribe();
@@ -56771,7 +56786,7 @@ const createPiRunner = (options) => {
56771
56786
  id: options.model.id
56772
56787
  },
56773
56788
  research: (spec, prompt, { signal }) => phase(spec, prompt, signal),
56774
- act: (spec, prompt, { signal, mode }) => phase(spec, prompt, signal, mode),
56789
+ act: (spec, prompt, { signal }) => phase(spec, prompt, signal, true),
56775
56790
  async close() {
56776
56791
  agent?.abort();
56777
56792
  await agent?.waitForIdle();
@@ -56785,21 +56800,36 @@ const acquireWorkflowRunner = async (options) => {
56785
56800
  const provider = id.slice(0, slash);
56786
56801
  const model = builtinModels().getModel(provider, id.slice(slash + 1));
56787
56802
  if (!model) throw new Error(`Unknown Pi model: ${id}`);
56788
- if (!getEnvApiKey(provider)) {
56803
+ if (!getEnvApiKey(provider)?.trim()) {
56789
56804
  const names = findEnvKeys(provider, new Proxy({}, { get: (_target, key) => typeof key === "string" ? "configured" : void 0 }));
56790
56805
  throw new Error(`Missing Pi credentials for ${provider}; set ${names?.join(" or ") ?? `${provider} provider credentials`}.`);
56791
56806
  }
56807
+ let executor = options.executor;
56808
+ if (executor === void 0) {
56809
+ const baseUrl = process.env["EXECUTOR_BASE_URL"]?.trim();
56810
+ if (!baseUrl) throw new Error("Missing Executor configuration; set EXECUTOR_BASE_URL before starting a workflow.");
56811
+ try {
56812
+ const url = new URL(baseUrl);
56813
+ if (url.protocol !== "http:" && url.protocol !== "https:") throw new Error("expected http: or https:");
56814
+ executor = await createExecutorToolset({ policy: "decline" });
56815
+ } catch (cause) {
56816
+ throw new Error(`Invalid workflow Executor configuration: ${cause instanceof Error ? cause.message : String(cause)}`, { cause });
56817
+ }
56818
+ }
56792
56819
  return createPiRunner({
56793
56820
  root: options.root,
56794
56821
  presetDirectory: resolve(options.root, options.config.presetDirectory),
56795
56822
  model,
56796
56823
  limit: options.limit,
56797
56824
  ...options.runsDirectory === void 0 ? {} : { runsDirectory: options.runsDirectory },
56825
+ ...options.repositoryRoot === void 0 ? {} : { repositoryRoot: options.repositoryRoot },
56826
+ ...options.runDirectory === void 0 ? {} : { runDirectory: options.runDirectory },
56827
+ ...options.resume === void 0 ? {} : { resume: options.resume },
56798
56828
  ...options.additionalTools === void 0 ? {} : { additionalTools: options.additionalTools },
56799
- executor: options.executor ?? await createExecutorToolset({ policy: "decline" })
56829
+ executor
56800
56830
  });
56801
56831
  };
56802
56832
  //#endregion
56803
56833
  export { WorkflowRunnerError, acquireWorkflowRunner, composeSystemPrompt, createPiRunner, envApiKeyAuth as n, lazyOAuth as r, validateToolArguments as t, totalUsage };
56804
56834
 
56805
- //# sourceMappingURL=pi-D3mMmYey.js.map
56835
+ //# sourceMappingURL=pi-Bz4BgZdC.js.map