pagegraph 0.8.1 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -35710,7 +35710,7 @@ const runWith = (command, config) => {
35710
35710
  };
35711
35711
  //#endregion
35712
35712
  //#region package.json
35713
- var version = "0.8.1";
35713
+ var version = "0.8.2";
35714
35714
  //#endregion
35715
35715
  //#region src/core/projections.ts
35716
35716
  const escapeXml = (value) => value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
@@ -43433,7 +43433,7 @@ const TranscriptSchema = Struct({ messages: ArraySchema(Unknown) });
43433
43433
  const decodeTextPart = decodeUnknownOption(TextPartSchema);
43434
43434
  const decodeAssistantMessage = decodeUnknownOption(AssistantMessageSchema);
43435
43435
  const decodeTranscript = decodeUnknownSync(TranscriptSchema);
43436
- const parseState = (transcript) => {
43436
+ const parseWorkflowState = (transcript) => {
43437
43437
  const candidates = decodeTranscript(transcript).messages.flatMap((message) => {
43438
43438
  const assistant = decodeAssistantMessage(message);
43439
43439
  if (isNone(assistant)) return [];
@@ -43452,6 +43452,25 @@ const parseState = (transcript) => {
43452
43452
  }
43453
43453
  throw new Error("The SEO agent did not return a valid workflow JSON object.");
43454
43454
  };
43455
+ const parseWorkflowStateWithRepair = async (transcript, repair) => {
43456
+ try {
43457
+ return {
43458
+ state: parseWorkflowState(transcript),
43459
+ transcript
43460
+ };
43461
+ } catch {
43462
+ const repaired = await repair();
43463
+ return {
43464
+ state: parseWorkflowState(repaired),
43465
+ transcript: repaired
43466
+ };
43467
+ }
43468
+ };
43469
+ const STATE_REPAIR_PROMPT = [
43470
+ "Your previous turn did not end with the workflow JSON object requested by the original prompt.",
43471
+ "Do not call tools, add commentary, or wrap the response in Markdown.",
43472
+ "Return only one valid JSON object matching the original JSON Schema, using the evidence already collected."
43473
+ ].join(" ");
43455
43474
  const decodeToolPart = decodeUnknownOption(Struct({
43456
43475
  type: Literal("tool"),
43457
43476
  id: String$6,
@@ -43515,14 +43534,14 @@ const interactionEventError = (event, sessionId) => {
43515
43534
  if (form !== null && typeof form === "object" && form["sessionID"] === sessionId) return /* @__PURE__ */ new Error("OpenCode requested a form; embedded PageGraph workflows are noninteractive.");
43516
43535
  }
43517
43536
  };
43518
- const waitForIdle = async (host, sessionId, timeoutMs, after) => {
43537
+ const waitForIdle = async (host, sessionId, options) => {
43519
43538
  const controller = new AbortController();
43520
- const timer = setTimeout(() => controller.abort(), timeoutMs);
43539
+ const timer = setTimeout(() => controller.abort(), options.timeoutMs);
43521
43540
  try {
43522
43541
  for await (const event of host.sessions.log({
43523
43542
  sessionID: sessionId,
43524
43543
  follow: true,
43525
- after
43544
+ after: options.after
43526
43545
  }, { signal: controller.signal })) {
43527
43546
  const interactionError = interactionEventError(event, sessionId);
43528
43547
  if (interactionError !== void 0) throw interactionError;
@@ -43530,6 +43549,9 @@ const waitForIdle = async (host, sessionId, timeoutMs, after) => {
43530
43549
  if (event.type === "session.execution.failed" && event.data.sessionID === sessionId) throw new Error(`OpenCode session failed: ${JSON.stringify(event.data.error)}`);
43531
43550
  if (event.type === "session.execution.interrupted" && event.data.sessionID === sessionId) throw new Error(`OpenCode session was interrupted: ${event.data.reason}.`);
43532
43551
  }
43552
+ } catch (cause) {
43553
+ if (controller.signal.aborted) throw new Error(`OpenCode session did not complete within ${options.configuredTimeoutMs ?? options.timeoutMs}ms.`, { cause });
43554
+ throw cause;
43533
43555
  } finally {
43534
43556
  clearTimeout(timer);
43535
43557
  }
@@ -43556,22 +43578,62 @@ const acquireWorkflowHost = async (options) => {
43556
43578
  sessionID: sessionId,
43557
43579
  permissions: [...workflowOptions.permissions]
43558
43580
  });
43581
+ const configuredTimeoutMs = options.timeoutMs ?? 18e4;
43582
+ const deadline = Date.now() + configuredTimeoutMs;
43583
+ const remaining = () => Math.max(0, deadline - Date.now());
43559
43584
  await host.sessions.prompt({
43560
43585
  sessionID: sessionId,
43561
43586
  text: prompt,
43562
43587
  skills: workflowOptions.skills.map((id) => ({ id }))
43563
43588
  });
43564
- const cursor = await waitForIdle(host, sessionId, options.timeoutMs ?? 18e4, cursors.get(sessionId));
43589
+ let cursor = await waitForIdle(host, sessionId, {
43590
+ timeoutMs: remaining(),
43591
+ configuredTimeoutMs,
43592
+ after: cursors.get(sessionId)
43593
+ });
43565
43594
  cursors.set(sessionId, cursor);
43566
- const transcript = await host.sessions.export({
43595
+ let transcript = await host.sessions.export({
43567
43596
  sessionID: sessionId,
43568
43597
  sanitize: false
43569
43598
  });
43599
+ const parsed = await parseWorkflowStateWithRepair(transcript, async () => {
43600
+ const priorPermissions = [...workflowOptions.permissions ?? []];
43601
+ await host.sessions.update({
43602
+ sessionID: sessionId,
43603
+ permissions: [{
43604
+ action: "*",
43605
+ resource: "*",
43606
+ effect: "deny"
43607
+ }]
43608
+ });
43609
+ try {
43610
+ await host.sessions.prompt({
43611
+ sessionID: sessionId,
43612
+ text: STATE_REPAIR_PROMPT
43613
+ });
43614
+ cursor = await waitForIdle(host, sessionId, {
43615
+ timeoutMs: remaining(),
43616
+ configuredTimeoutMs,
43617
+ after: cursor
43618
+ });
43619
+ cursors.set(sessionId, cursor);
43620
+ transcript = await host.sessions.export({
43621
+ sessionID: sessionId,
43622
+ sanitize: false
43623
+ });
43624
+ return transcript;
43625
+ } finally {
43626
+ await host.sessions.update({
43627
+ sessionID: sessionId,
43628
+ permissions: priorPermissions
43629
+ });
43630
+ }
43631
+ });
43570
43632
  return {
43571
- state: parseState(transcript),
43633
+ state: parsed.state,
43572
43634
  sessionId,
43573
- transcript,
43574
- executor: collectExecutorEvidence(transcript)
43635
+ transcript: parsed.transcript,
43636
+ executor: collectExecutorEvidence(parsed.transcript)
43575
43637
  };
43576
43638
  };
43577
43639
  return {