pagegraph 0.14.0 → 0.15.0

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-B6zg_Z3Z.js → dist-Br2oOB2Q.js} +2 -2
  20. package/dist/{dist-B6zg_Z3Z.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-Bvw6J0gh.js → pi-Bz4BgZdC.js} +207 -167
  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 +6 -4
  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 +2 -2
  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-Bvw6J0gh.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, 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, 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-B6zg_Z3Z.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 */
@@ -55805,7 +55805,7 @@ var __exportAll = (all, no_symbols) => {
55805
55805
  return target;
55806
55806
  };
55807
55807
  //#endregion
55808
- //#region node_modules/@pi-ext/executor/dist/tools-BVfUkejO.js
55808
+ //#region node_modules/@pi-ext/executor/dist/tools-C-jym3aZ.js
55809
55809
  /** The Executor connection settings are missing or unreadable. */
55810
55810
  var ExecutorConfigError = class extends TaggedError()("ExecutorConfigError", { message: String$1 }) {};
55811
55811
  /**
@@ -55854,14 +55854,18 @@ const SearchItem = Struct({
55854
55854
  score: Number$1
55855
55855
  });
55856
55856
  const SearchResponse = Struct({ items: ArraySchema(SearchItem) });
55857
- /** The fields of `GET /api/tools/schema` this package reads. */
55857
+ /**
55858
+ * The fields of `GET /api/tools/schema` this package reads. The server sends
55859
+ * `null` for a missing preview (MCP tools have no TypeScript definitions), so
55860
+ * every optional field also accepts `null`.
55861
+ */
55858
55862
  const ToolSchemaView = Struct({
55859
55863
  address: String$1,
55860
- name: optional(String$1),
55861
- description: optional(String$1),
55862
- inputTypeScript: optional(String$1),
55863
- outputTypeScript: optional(String$1),
55864
- typeScriptDefinitions: optional(Record(String$1, String$1))
55864
+ name: optional(NullOr(String$1)),
55865
+ description: optional(NullOr(String$1)),
55866
+ inputTypeScript: optional(NullOr(String$1)),
55867
+ outputTypeScript: optional(NullOr(String$1)),
55868
+ typeScriptDefinitions: optional(NullOr(Record(String$1, String$1)))
55865
55869
  });
55866
55870
  /**
55867
55871
  * One tool call made by an execution. Optional on the wire until the Executor
@@ -56068,7 +56072,8 @@ const SearchHitSchema = _Object_({
56068
56072
  description: Optional(String$3()),
56069
56073
  inputTypeScript: Optional(String$3()),
56070
56074
  outputTypeScript: Optional(String$3()),
56071
- typeScriptDefinitions: Optional(Record$1(String$3(), String$3()))
56075
+ typeScriptDefinitions: Optional(Record$1(String$3(), String$3())),
56076
+ detailsError: Optional(String$3())
56072
56077
  });
56073
56078
  const SearchOutput = _Object_({ items: _Array_(SearchHitSchema) });
56074
56079
  const SEARCH_TOOL = {
@@ -56112,6 +56117,7 @@ const searchText = (items) => {
56112
56117
  lines.push("", `tools.${item.path}${description ? ` — ${description}` : ""}`);
56113
56118
  if (item.inputTypeScript) lines.push(` input: ${item.inputTypeScript}`);
56114
56119
  if (item.outputTypeScript) lines.push(` output: ${item.outputTypeScript}`);
56120
+ if (item.detailsError) lines.push(` types unavailable: ${item.detailsError}`);
56115
56121
  for (const [name, body] of Object.entries(item.typeScriptDefinitions ?? {})) definitions.set(name, body);
56116
56122
  }
56117
56123
  if (definitions.size > 0) {
@@ -56127,15 +56133,19 @@ const search = (client, params) => gen(function* () {
56127
56133
  });
56128
56134
  if (!params.includeDetails) return items;
56129
56135
  return yield* forEach(items, (item) => client.describe(item.path).pipe(map((view) => {
56130
- const roots = [view.inputTypeScript ?? "", view.outputTypeScript ?? ""];
56131
- const definitions = reachableDefinitions(roots, view.typeScriptDefinitions ?? {});
56136
+ const inputTypeScript = view.inputTypeScript ?? void 0;
56137
+ const outputTypeScript = view.outputTypeScript ?? void 0;
56138
+ const definitions = reachableDefinitions([inputTypeScript ?? "", outputTypeScript ?? ""], view.typeScriptDefinitions ?? {});
56132
56139
  return {
56133
56140
  ...item,
56134
- ...view.inputTypeScript === void 0 ? {} : { inputTypeScript: view.inputTypeScript },
56135
- ...view.outputTypeScript === void 0 ? {} : { outputTypeScript: view.outputTypeScript },
56141
+ ...inputTypeScript === void 0 ? {} : { inputTypeScript },
56142
+ ...outputTypeScript === void 0 ? {} : { outputTypeScript },
56136
56143
  ...Object.keys(definitions).length === 0 ? {} : { typeScriptDefinitions: definitions }
56137
56144
  };
56138
- })), { concurrency: DESCRIBE_CONCURRENCY });
56145
+ }), catch_((error) => succeed({
56146
+ ...item,
56147
+ detailsError: error.message
56148
+ }))), { concurrency: DESCRIBE_CONCURRENCY });
56139
56149
  });
56140
56150
  const ExecuteParams = _Object_({ code: String$3({ description: "TypeScript to run in Executor's sandbox. Call tools as `await tools.<path>(input)` and end with a top-level `return`." }) });
56141
56151
  const EXECUTE_TOOL = {
@@ -56311,6 +56321,34 @@ const executorTools = (options) => [{
56311
56321
  }];
56312
56322
  //#endregion
56313
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
+ };
56314
56352
  const executionEvidence = (record) => {
56315
56353
  if (record.isError) return void 0;
56316
56354
  const succeeded = (record.toolCalls ?? []).filter((call) => !call.isError).map((call) => call.path);
@@ -56358,74 +56396,15 @@ const repositoryToolNames = /* @__PURE__ */ new Set([
56358
56396
  "list_files",
56359
56397
  "search_text"
56360
56398
  ]);
56361
- const writeToolNames = /* @__PURE__ */ new Set(["write_file", "edit_file"]);
56362
- const missingPath = (cause) => cause instanceof Error && "code" in cause && cause.code === "ENOENT";
56363
- const resolveWritablePath = async (path) => {
56364
- let ancestor = path;
56365
- const suffix = [];
56366
- while (true) try {
56367
- return resolve(await realpath(ancestor), ...suffix);
56368
- } catch (cause) {
56369
- if (!missingPath(cause)) throw cause;
56370
- try {
56371
- if ((await lstat(ancestor)).isSymbolicLink()) throw new Error(`Repository path has a dangling symlink: ${path}`);
56372
- } catch (statCause) {
56373
- if (!missingPath(statCause)) throw statCause;
56374
- }
56375
- const parent = dirname(ancestor);
56376
- if (parent === ancestor) throw cause;
56377
- suffix.unshift(relative(parent, ancestor));
56378
- ancestor = parent;
56379
- }
56380
- };
56381
- const writableRepositoryPath = async (root, path, options) => {
56382
- const projectRoot = await realpath(root);
56383
- const requested = resolve(projectRoot, path);
56384
- if (!insideRoot(projectRoot, requested)) throw new Error(`Repository path escapes project root: ${path}`);
56385
- const resolved = await resolveWritablePath(requested);
56386
- if (!insideRoot(projectRoot, resolved)) throw new Error(`Repository path escapes project root through a symlink: ${path}`);
56387
- 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}`);
56388
- const forbidden = [
56389
- resolve(projectRoot, ".git"),
56390
- resolve(projectRoot, "node_modules"),
56391
- resolve(projectRoot, options.runsDirectory),
56392
- resolve(projectRoot, options.presetDirectory)
56393
- ];
56394
- for (const directory of forbidden) {
56395
- const actual = await resolveWritablePath(directory);
56396
- if (insideRoot(directory, requested) || insideRoot(actual, resolved)) throw new Error(`Repository write targets a protected directory: ${path}`);
56397
- }
56398
- const existing = await lstat(resolved).catch((error) => {
56399
- if (error instanceof Error && "code" in error && error.code === "ENOENT") return void 0;
56400
- throw error;
56401
- });
56402
- if (existing !== void 0 && existing.nlink > 1) throw new Error(`Repository write targets a hard-linked file: ${path}`);
56403
- return resolved;
56404
- };
56405
- const insideRoot = (root, path) => {
56406
- const pathFromRoot = relative(root, path);
56407
- return pathFromRoot !== ".." && !pathFromRoot.startsWith(`..${sep}`) && !isAbsolute(pathFromRoot);
56408
- };
56409
- const repositoryPath = async (root, path) => {
56410
- const projectRoot = await realpath(root);
56411
- const requested = resolve(projectRoot, path);
56412
- if (!insideRoot(projectRoot, requested) && !insideRoot(resolve(root), requested)) throw new Error(`Repository path escapes project root: ${path}`);
56413
- const resolved = await realpath(requested);
56414
- if (!insideRoot(projectRoot, resolved)) throw new Error(`Repository path escapes project root through a symlink: ${path}`);
56415
- return resolved;
56416
- };
56417
56399
  const pathArgument = (args) => {
56418
56400
  if (typeof args !== "object" || args === null || !("path" in args) || typeof args.path !== "string") throw new Error("Repository tools require a string path");
56419
56401
  return args.path;
56420
56402
  };
56421
- const guardRepositoryToolCall = (root, writeOptions) => async ({ toolCall, args }, signal) => {
56422
- 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;
56423
56405
  try {
56424
56406
  signal?.throwIfAborted();
56425
- if (writeToolNames.has(toolCall.name)) {
56426
- if (!writeOptions) throw new Error("Repository writes are unavailable in this workflow phase");
56427
- await writableRepositoryPath(root, pathArgument(args), writeOptions);
56428
- } else await repositoryPath(root, pathArgument(args));
56407
+ await resolveRepositoryReadPath(readOptions?.repositoryRoot ?? root, pathArgument(args), readOptions);
56429
56408
  return;
56430
56409
  } catch (error) {
56431
56410
  return {
@@ -56434,15 +56413,20 @@ const guardRepositoryToolCall = (root, writeOptions) => async ({ toolCall, args
56434
56413
  };
56435
56414
  }
56436
56415
  };
56437
- const readBoundedFile = async (path, signal) => {
56416
+ const readBoundedFile = async (path, signal, offset = 0, maxBytes = MAX_FILE_BYTES) => {
56438
56417
  signal?.throwIfAborted();
56439
56418
  const file = await open(path, "r");
56440
56419
  try {
56441
56420
  if (!(await file.stat()).isFile()) throw new Error(`Repository path is not a regular file: ${path}`);
56442
- const buffer = Buffer.alloc(65537);
56443
- 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);
56444
56423
  signal?.throwIfAborted();
56445
- 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}]` : "");
56446
56430
  } finally {
56447
56431
  await file.close();
56448
56432
  }
@@ -56454,14 +56438,14 @@ const result = (text) => ({
56454
56438
  }],
56455
56439
  details: void 0
56456
56440
  });
56457
- const discoverFiles = async (root, directory, recursive, signal) => {
56441
+ const discoverFiles = async (root, directory, recursive, signal, options) => {
56458
56442
  const files = [];
56459
56443
  const pending = [directory];
56460
56444
  let inspected = 0;
56461
56445
  while (pending.length > 0 && inspected < MAX_ENTRIES) {
56462
56446
  signal?.throwIfAborted();
56463
56447
  const next = pending.shift();
56464
- 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));
56465
56449
  for (const entry of entries) {
56466
56450
  if (++inspected > MAX_ENTRIES) break;
56467
56451
  const path = resolve(next, entry.name);
@@ -56471,13 +56455,26 @@ const discoverFiles = async (root, directory, recursive, signal) => {
56471
56455
  }
56472
56456
  return files;
56473
56457
  };
56474
- 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 = {}) => [
56475
56465
  {
56476
56466
  name: "read_file",
56477
56467
  label: "Read repository file",
56478
- description: "Read a UTF-8 file within the project root, limited to 64 KiB.",
56479
- parameters: _Object_({ path: String$3() }),
56480
- 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)))
56481
56478
  },
56482
56479
  {
56483
56480
  name: "list_files",
@@ -56492,8 +56489,8 @@ const createRepositoryTools = (root) => [
56492
56489
  const recursive = typeof args === "object" && args !== null && "recursive" in args ? args.recursive : false;
56493
56490
  if (typeof recursive !== "boolean") throw new Error("list_files recursive must be a boolean");
56494
56491
  const projectRoot = await realpath(root);
56495
- const directory = await repositoryPath(root, path);
56496
- 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);
56497
56494
  return result(files.map((file) => relative(projectRoot, file)).join("\n").slice(0, MAX_OUTPUT_CHARACTERS));
56498
56495
  }
56499
56496
  },
@@ -56510,11 +56507,11 @@ const createRepositoryTools = (root) => [
56510
56507
  const text = typeof args === "object" && args !== null && "text" in args ? args.text : void 0;
56511
56508
  if (typeof text !== "string" || text.length === 0) throw new Error("search_text requires nonempty literal text");
56512
56509
  const projectRoot = await realpath(root);
56513
- const directory = await repositoryPath(root, path);
56514
- 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);
56515
56512
  const matches = [];
56516
56513
  for (const file of files) {
56517
- const content = await readBoundedFile(await repositoryPath(root, file), signal);
56514
+ const content = await readBoundedFile(await resolveRepositoryReadPath(root, file, options), signal);
56518
56515
  if (content.includes("\0")) continue;
56519
56516
  for (const [index, line] of content.split("\n").entries()) {
56520
56517
  if (line.includes(text)) matches.push(`${relative(projectRoot, file)}:${index + 1}:${line}`);
@@ -56526,51 +56523,6 @@ const createRepositoryTools = (root) => [
56526
56523
  }
56527
56524
  }
56528
56525
  ];
56529
- const stringArgument = (args, key) => {
56530
- if (typeof args !== "object" || args === null || !(key in args) || typeof Reflect.get(args, key) !== "string") throw new Error(`Repository tools require a string ${key}`);
56531
- return Reflect.get(args, key);
56532
- };
56533
- const createRepositoryWriteTools = (root, options) => [{
56534
- name: "write_file",
56535
- label: "Write repository file",
56536
- description: "Create or overwrite a UTF-8 repository file. Protected directories and symlink escapes are blocked.",
56537
- parameters: _Object_({
56538
- path: String$3(),
56539
- content: String$3()
56540
- }),
56541
- execute: async (_id, args, signal) => {
56542
- signal?.throwIfAborted();
56543
- const requested = pathArgument(args);
56544
- const path = await writableRepositoryPath(root, requested, options);
56545
- await mkdir(dirname(path), { recursive: true });
56546
- signal?.throwIfAborted();
56547
- await writeFile(await writableRepositoryPath(root, pathArgument(args), options), stringArgument(args, "content"), "utf8");
56548
- return result(`Wrote ${pathArgument(args)}`);
56549
- }
56550
- }, {
56551
- name: "edit_file",
56552
- label: "Edit repository file",
56553
- description: "Replace exact text in a UTF-8 repository file. oldText must match exactly one region; protected directories and symlink escapes are blocked.",
56554
- parameters: _Object_({
56555
- path: String$3(),
56556
- oldText: String$3({ minLength: 1 }),
56557
- newText: String$3()
56558
- }),
56559
- execute: async (_id, args, signal) => {
56560
- signal?.throwIfAborted();
56561
- const oldText = stringArgument(args, "oldText");
56562
- const newText = stringArgument(args, "newText");
56563
- if (oldText.length === 0) throw new Error("edit_file oldText must be nonempty");
56564
- const requested = pathArgument(args);
56565
- const path = await writableRepositoryPath(root, requested, options);
56566
- const content = await readFile(path, "utf8");
56567
- const index = content.indexOf(oldText);
56568
- if (index < 0 || content.indexOf(oldText, index + 1) >= 0) throw new Error("edit_file oldText must match exactly once");
56569
- signal?.throwIfAborted();
56570
- await writeFile(await writableRepositoryPath(root, pathArgument(args), options), content.slice(0, index) + newText + content.slice(index + oldText.length), "utf8");
56571
- return result(`Edited ${pathArgument(args)}`);
56572
- }
56573
- }];
56574
56526
  //#endregion
56575
56527
  //#region src/workflows/pi.ts
56576
56528
  const MAX_REJECTED_SUBMISSIONS = 3;
@@ -56632,36 +56584,97 @@ var WorkflowRunnerError = class extends Error {
56632
56584
  };
56633
56585
  const createPiRunner = (options) => {
56634
56586
  let agent;
56635
- let researched = false;
56636
- 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) => {
56637
56632
  const assertDeadline = (messages = []) => {
56638
56633
  if (signal.aborted) throw new WorkflowRunnerError(`Workflow deadline exceeded or run aborted: ${String(signal.reason)}`, {
56639
56634
  messages,
56640
56635
  usage: totalUsage(messages),
56641
- executor: executorEvidence(options.executor.trace)
56636
+ executor: evidence()
56642
56637
  }, { cause: signal.reason });
56643
56638
  };
56644
56639
  assertDeadline(agent?.state.messages);
56645
- if (mode !== void 0 && !researched) throw new Error("Workflow action requires a completed research conversation");
56646
- 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;
56647
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
+ };
56648
56655
  let state;
56649
56656
  let submitted = false;
56650
56657
  let rejected = 0;
56651
56658
  let lastIssues = "No structured result was submitted.";
56659
+ let lastSubmission;
56660
+ let rejectedItems;
56652
56661
  const rawSubmissions = /* @__PURE__ */ new Map();
56653
56662
  const submit = {
56654
56663
  name: "submit_result",
56655
56664
  label: "Submit workflow result",
56656
56665
  description: "Validate and submit the final workflow state after collecting Executor evidence.",
56657
- parameters: Unsafe(mode === void 0 ? spec.stateJsonSchema : actionStateJsonSchema),
56658
- 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
+ },
56659
56671
  execute: async (_id, params) => {
56660
56672
  try {
56661
- const decoded = mode === void 0 ? decodeResearchState(spec, rawSubmissions.get(_id) ?? params, options.limit) : decodeActionState(rawSubmissions.get(_id) ?? params);
56662
- const evidence = executorEvidence(options.executor.trace);
56663
- if (mode === void 0 && (evidence.searches.length === 0 || evidence.calls.length === 0)) throw new Error([
56664
- `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}).`,
56665
56678
  "Catalog searches and schema discovery alone do not satisfy this workflow.",
56666
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.",
56667
56680
  "Preserve provider errors and empty datasets honestly; do not invent evidence or mutate provider state."
@@ -56690,29 +56703,26 @@ const createPiRunner = (options) => {
56690
56703
  }
56691
56704
  }
56692
56705
  };
56693
- const writeOptions = {
56694
- presetDirectory: options.presetDirectory,
56695
- runsDirectory: options.runsDirectory ?? resolve(options.root, ".pagegraph/runs")
56696
- };
56697
56706
  const tools = [
56698
- ...options.executor.tools,
56699
- ...createRepositoryTools(options.root),
56707
+ ...executor.tools,
56708
+ ...createRepositoryTools(readOptions.repositoryRoot, readOptions),
56700
56709
  ...options.additionalTools ?? [],
56701
- ...mode === "write" ? createRepositoryWriteTools(options.root, writeOptions) : [],
56702
56710
  submit
56703
56711
  ];
56704
56712
  if (systemPrompt !== void 0) {
56705
- researched = false;
56713
+ if (!action) researched = false;
56706
56714
  agent = new Agent({
56707
56715
  initialState: {
56708
56716
  systemPrompt,
56709
56717
  model: options.model,
56710
- tools
56718
+ tools,
56719
+ ...resume === void 0 ? {} : { messages: [...resume.agent.messages] }
56711
56720
  },
56712
56721
  streamFn: options.streamFn ?? streamSimple,
56713
56722
  getApiKey: getEnvApiKey,
56714
56723
  toolExecution: "sequential"
56715
56724
  });
56725
+ resume = void 0;
56716
56726
  }
56717
56727
  if (!agent) throw new Error("Workflow action requires a research conversation");
56718
56728
  agent.state.tools = tools;
@@ -56723,7 +56733,7 @@ const createPiRunner = (options) => {
56723
56733
  terminate: true
56724
56734
  };
56725
56735
  if (context.toolCall.name === "submit_result") rawSubmissions.set(context.toolCall.id, context.toolCall.arguments);
56726
- return guardRepositoryToolCall(options.root, mode === "write" ? writeOptions : void 0)?.(context, signal);
56736
+ return guardRepositoryToolCall(options.root, readOptions)?.(context, signal);
56727
56737
  };
56728
56738
  agent.finishTurn = () => submitted || rejected >= MAX_REJECTED_SUBMISSIONS ? { action: "end" } : void 0;
56729
56739
  const current = agent;
@@ -56741,15 +56751,30 @@ const createPiRunner = (options) => {
56741
56751
  const result = {
56742
56752
  messages: current.state.messages,
56743
56753
  usage: totalUsage(current.state.messages),
56744
- executor: executorEvidence(options.executor.trace)
56754
+ executor: evidence()
56745
56755
  };
56746
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 {}
56747
56763
  if (!submitted) throw new WorkflowRunnerError(`Workflow result rejected: ${lastIssues}${current.state.errorMessage ? `\n${current.state.errorMessage}` : ""}`, result);
56748
- if (mode === void 0) researched = true;
56764
+ if (!action) researched = true;
56749
56765
  return {
56750
56766
  ...result,
56751
- state
56767
+ state,
56768
+ ...rejectedItems === void 0 ? {} : { rejectedItems }
56752
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 });
56753
56778
  } finally {
56754
56779
  signal.removeEventListener("abort", abort);
56755
56780
  unsubscribe();
@@ -56761,7 +56786,7 @@ const createPiRunner = (options) => {
56761
56786
  id: options.model.id
56762
56787
  },
56763
56788
  research: (spec, prompt, { signal }) => phase(spec, prompt, signal),
56764
- act: (spec, prompt, { signal, mode }) => phase(spec, prompt, signal, mode),
56789
+ act: (spec, prompt, { signal }) => phase(spec, prompt, signal, true),
56765
56790
  async close() {
56766
56791
  agent?.abort();
56767
56792
  await agent?.waitForIdle();
@@ -56775,21 +56800,36 @@ const acquireWorkflowRunner = async (options) => {
56775
56800
  const provider = id.slice(0, slash);
56776
56801
  const model = builtinModels().getModel(provider, id.slice(slash + 1));
56777
56802
  if (!model) throw new Error(`Unknown Pi model: ${id}`);
56778
- if (!getEnvApiKey(provider)) {
56803
+ if (!getEnvApiKey(provider)?.trim()) {
56779
56804
  const names = findEnvKeys(provider, new Proxy({}, { get: (_target, key) => typeof key === "string" ? "configured" : void 0 }));
56780
56805
  throw new Error(`Missing Pi credentials for ${provider}; set ${names?.join(" or ") ?? `${provider} provider credentials`}.`);
56781
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
+ }
56782
56819
  return createPiRunner({
56783
56820
  root: options.root,
56784
56821
  presetDirectory: resolve(options.root, options.config.presetDirectory),
56785
56822
  model,
56786
56823
  limit: options.limit,
56787
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 },
56788
56828
  ...options.additionalTools === void 0 ? {} : { additionalTools: options.additionalTools },
56789
- executor: options.executor ?? await createExecutorToolset({ policy: "decline" })
56829
+ executor
56790
56830
  });
56791
56831
  };
56792
56832
  //#endregion
56793
56833
  export { WorkflowRunnerError, acquireWorkflowRunner, composeSystemPrompt, createPiRunner, envApiKeyAuth as n, lazyOAuth as r, validateToolArguments as t, totalUsage };
56794
56834
 
56795
- //# sourceMappingURL=pi-Bvw6J0gh.js.map
56835
+ //# sourceMappingURL=pi-Bz4BgZdC.js.map