@hachej/boring-agent 0.1.37 → 0.1.39

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.
@@ -73,6 +73,17 @@ interface AgentHarness {
73
73
  getSystemPrompt?: (sessionId: string) => string | undefined;
74
74
  /** Reload native agent resources/extensions for an existing session. */
75
75
  reloadSession?: (sessionId: string) => Promise<boolean>;
76
+ /**
77
+ * Resource (skill/extension) load diagnostics for an existing session.
78
+ * Returns `[]` when the session has no live agent session yet. Lets the
79
+ * /reload route and the `plugin_diagnostics` tool surface silent
80
+ * skill/extension load failures back to the UI and the agent.
81
+ */
82
+ getResourceDiagnostics?: (sessionId: string) => Array<{
83
+ source: string;
84
+ message: string;
85
+ path?: string;
86
+ }>;
76
87
  /** List slash commands registered in the agent runtime for a given session. */
77
88
  getSlashCommands?: (sessionId: string, ctx: RunContext) => ReadonlyArray<AgentSlashCommandSummary> | Promise<ReadonlyArray<AgentSlashCommandSummary>>;
78
89
  /**
@@ -314,6 +314,7 @@ interface RemotePiSessionOptions {
314
314
  };
315
315
  setTimeoutFn?: typeof globalThis.setTimeout;
316
316
  clearTimeoutFn?: typeof globalThis.clearTimeout;
317
+ requestTimeoutMs?: number;
317
318
  }
318
319
  interface RemotePiSessionLargeStateWarning {
319
320
  type: 'large-state';
@@ -358,6 +359,7 @@ declare class RemotePiSession {
358
359
  private readonly storageScope;
359
360
  private readonly setTimeoutFn;
360
361
  private readonly clearTimeoutFn;
362
+ private readonly requestTimeoutMs;
361
363
  private generation;
362
364
  private streamRunId;
363
365
  private reconnectAttempt;
@@ -4441,6 +4441,7 @@ function schedulePiChatReconnect({
4441
4441
  var SUPPORTED_PROTOCOL_VERSION = 1;
4442
4442
  var DEFAULT_RECONNECT_BASE_MS = 1e3;
4443
4443
  var DEFAULT_RECONNECT_MAX_MS = 3e4;
4444
+ var DEFAULT_REQUEST_TIMEOUT_MS = 15e3;
4444
4445
  var DEFAULT_LARGE_STATE_WARNING_BYTES = 5 * 1024 * 1024;
4445
4446
  var DEFAULT_LARGE_STATE_WARNING_MESSAGES = 300;
4446
4447
  var EVENT_TYPE_RING_LIMIT = 20;
@@ -4456,6 +4457,7 @@ var RemotePiSession = class {
4456
4457
  this.fetchImpl = options.fetch ?? globalThis.fetch.bind(globalThis);
4457
4458
  this.setTimeoutFn = options.setTimeoutFn ?? globalThis.setTimeout;
4458
4459
  this.clearTimeoutFn = options.clearTimeoutFn ?? globalThis.clearTimeout;
4460
+ this.requestTimeoutMs = options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
4459
4461
  this.store = createPiChatStore(createInitialPiChatState({
4460
4462
  sessionId: options.sessionId,
4461
4463
  workspaceId: options.workspaceId,
@@ -4471,6 +4473,7 @@ var RemotePiSession = class {
4471
4473
  storageScope;
4472
4474
  setTimeoutFn;
4473
4475
  clearTimeoutFn;
4476
+ requestTimeoutMs;
4474
4477
  generation = 0;
4475
4478
  streamRunId = 0;
4476
4479
  reconnectAttempt = 0;
@@ -4631,9 +4634,21 @@ var RemotePiSession = class {
4631
4634
  opened = true;
4632
4635
  onOpen?.();
4633
4636
  };
4637
+ let connectTimedOut = false;
4638
+ let connectTimer = globalThis.setTimeout(() => {
4639
+ connectTimedOut = true;
4640
+ controller.abort();
4641
+ }, this.requestTimeoutMs);
4642
+ const clearConnectTimer = () => {
4643
+ if (connectTimer !== void 0) {
4644
+ globalThis.clearTimeout(connectTimer);
4645
+ connectTimer = void 0;
4646
+ }
4647
+ };
4634
4648
  try {
4635
4649
  const headers = await this.requestHeaders();
4636
4650
  if (!this.isStreamActive(generation, runId)) {
4651
+ clearConnectTimer();
4637
4652
  markOpen();
4638
4653
  return;
4639
4654
  }
@@ -4642,6 +4657,7 @@ var RemotePiSession = class {
4642
4657
  headers,
4643
4658
  signal: controller.signal
4644
4659
  });
4660
+ clearConnectTimer();
4645
4661
  if (!this.isStreamActive(generation, runId)) {
4646
4662
  markOpen();
4647
4663
  return;
@@ -4699,10 +4715,14 @@ var RemotePiSession = class {
4699
4715
  this.scheduleReconnect(generation);
4700
4716
  }
4701
4717
  } catch (error) {
4718
+ clearConnectTimer();
4702
4719
  markOpen();
4703
- if (!this.isStreamActive(generation, runId) || shouldIgnoreStreamClose(error, controller)) return;
4704
- this.dispatchProtocolError(errorMessage(error, "Pi chat event stream disconnected."));
4720
+ if (!this.isStreamActive(generation, runId)) return;
4721
+ if (!connectTimedOut && shouldIgnoreStreamClose(error, controller)) return;
4722
+ this.dispatchProtocolError(connectTimedOut ? `Pi chat event stream timed out after ${this.requestTimeoutMs}ms.` : errorMessage(error, "Pi chat event stream disconnected."));
4705
4723
  this.scheduleReconnect(generation);
4724
+ } finally {
4725
+ clearConnectTimer();
4706
4726
  }
4707
4727
  }
4708
4728
  rehydrateAfterStreamReset(generation, options = {}) {
@@ -4755,12 +4775,21 @@ var RemotePiSession = class {
4755
4775
  async fetchJson(url, init) {
4756
4776
  const controller = new AbortController();
4757
4777
  this.fetchControllers.add(controller);
4778
+ let timedOut = false;
4779
+ const timer = globalThis.setTimeout(() => {
4780
+ timedOut = true;
4781
+ controller.abort();
4782
+ }, this.requestTimeoutMs);
4758
4783
  try {
4759
4784
  const response = await this.fetchImpl(url, { ...init, signal: controller.signal });
4760
4785
  const body = await safeReadJson(response);
4761
4786
  if (!response.ok) throw new RemotePiSessionHttpError(response.status, routeErrorMessage(body, `HTTP ${response.status}`), body);
4762
4787
  return body;
4788
+ } catch (error) {
4789
+ if (timedOut) throw new Error(`Request to ${url} timed out after ${this.requestTimeoutMs}ms.`);
4790
+ throw error;
4763
4791
  } finally {
4792
+ globalThis.clearTimeout(timer);
4764
4793
  this.fetchControllers.delete(controller);
4765
4794
  }
4766
4795
  }
@@ -1,5 +1,5 @@
1
- import { o as WorkspaceRuntimeContext, S as Sandbox, g as SandboxHandleStore, f as SandboxHandleRecord, W as Workspace, j as TelemetrySink, F as FileSearch, P as PluginRestartWarning, A as AgentTool, q as AgentHarnessFactory } from '../agentPluginEvents-DgNc3erX.js';
2
- export { r as AgentHarnessFactoryInput } from '../agentPluginEvents-DgNc3erX.js';
1
+ import { o as WorkspaceRuntimeContext, S as Sandbox, g as SandboxHandleStore, f as SandboxHandleRecord, W as Workspace, j as TelemetrySink, F as FileSearch, P as PluginRestartWarning, A as AgentTool, q as AgentHarnessFactory } from '../agentPluginEvents-CKrZLW3g.js';
2
+ export { r as AgentHarnessFactoryInput } from '../agentPluginEvents-CKrZLW3g.js';
3
3
  import { Sandbox as Sandbox$1 } from '@vercel/sandbox';
4
4
  import { FastifyInstance, FastifyRequest, FastifyPluginAsync } from 'fastify';
5
5
  import { PackageSource, ExtensionFactory, SettingsManager } from '@mariozechner/pi-coding-agent';
@@ -533,6 +533,19 @@ interface CreateAgentAppOptions {
533
533
  * the workspace plugin layer.
534
534
  */
535
535
  systemPromptDynamic?: () => string | undefined | Promise<string | undefined>;
536
+ /**
537
+ * Optional host callback returning current plugin/skill load diagnostics
538
+ * for this workspace. Surfaced by the `plugin_diagnostics` agent tool so the
539
+ * model can iterate on plugin/skill load errors after a /reload.
540
+ */
541
+ getPluginDiagnostics?: (args: {
542
+ workspaceId: string;
543
+ workspaceRoot: string;
544
+ }) => Promise<Array<{
545
+ source: string;
546
+ message: string;
547
+ pluginId?: string;
548
+ }>>;
536
549
  }
537
550
  declare function createAgentApp(opts?: CreateAgentAppOptions): Promise<FastifyInstance>;
538
551
 
@@ -611,6 +624,19 @@ interface RegisterAgentRoutesOptions {
611
624
  workspaceRoot: string;
612
625
  request: FastifyRequest;
613
626
  }) => void | ReloadHookResult | undefined | Promise<void | ReloadHookResult | undefined>;
627
+ /**
628
+ * Optional host callback returning current plugin/skill load diagnostics
629
+ * for a workspace. Surfaced by the `plugin_diagnostics` agent tool so the
630
+ * model can iterate on plugin/skill load errors after a /reload.
631
+ */
632
+ getPluginDiagnostics?: (args: {
633
+ workspaceId: string;
634
+ workspaceRoot: string;
635
+ }) => Promise<Array<{
636
+ source: string;
637
+ message: string;
638
+ pluginId?: string;
639
+ }>>;
614
640
  }
615
641
  /**
616
642
  * Fastify plugin that mounts agent routes onto a host app (typically core-built).
@@ -6564,6 +6564,40 @@ function createPiCodingAgentHarness(opts) {
6564
6564
  hasPiSession(sessionId) {
6565
6565
  return piSessions.has(sessionId);
6566
6566
  },
6567
+ /**
6568
+ * Surface Pi's skill/extension load diagnostics for a session so silent
6569
+ * load failures (bad SKILL.md, extension import errors) reach the UI and
6570
+ * the agent. Returns [] when the session has no live pi session yet.
6571
+ * The resourceLoader getters are synchronous.
6572
+ */
6573
+ getResourceDiagnostics(sessionId) {
6574
+ const handle = piSessions.get(sessionId);
6575
+ if (!handle) return [];
6576
+ const out = [];
6577
+ const seen = /* @__PURE__ */ new Set();
6578
+ const push = (entry) => {
6579
+ const key = `${entry.source}
6580
+ ${entry.message}`;
6581
+ if (seen.has(key)) return;
6582
+ seen.add(key);
6583
+ out.push(entry);
6584
+ };
6585
+ for (const diagnostic of handle.resourceLoader.getSkills().diagnostics) {
6586
+ push({
6587
+ source: "pi-skills",
6588
+ message: diagnostic.path && !diagnostic.message.includes(diagnostic.path) ? `${diagnostic.message} (${diagnostic.path})` : diagnostic.message,
6589
+ ...diagnostic.path ? { path: diagnostic.path } : {}
6590
+ });
6591
+ }
6592
+ for (const error of handle.resourceLoader.getExtensions().errors) {
6593
+ push({
6594
+ source: "pi-extensions",
6595
+ message: error.error.includes(error.path) ? error.error : `${error.error} (${error.path})`,
6596
+ path: error.path
6597
+ });
6598
+ }
6599
+ return out;
6600
+ },
6567
6601
  reloadSession: reloadPiSession,
6568
6602
  async getSlashCommands(sessionId, ctx) {
6569
6603
  const handle = await getOrCreatePiSession(sessionId, { sessionId, message: "" }, ctx);
@@ -8110,8 +8144,10 @@ function skillsRoutes(app, opts, done) {
8110
8144
  }));
8111
8145
  cached.set(cacheKey, { skills, expiresAt: now + CACHE_TTL_MS2 });
8112
8146
  return reply.code(200).send({ skills });
8113
- } catch {
8114
- return reply.code(200).send({ skills: [] });
8147
+ } catch (error) {
8148
+ const message = error instanceof Error ? error.message : String(error);
8149
+ request.log.warn({ err: error }, "[agent] failed to load skills");
8150
+ return reply.code(200).send({ skills: [], error: message });
8115
8151
  }
8116
8152
  });
8117
8153
  done();
@@ -8741,13 +8777,27 @@ function reloadRoutes(app, opts, done) {
8741
8777
  const hookResult = await opts.beforeReload?.();
8742
8778
  const reloaded = await opts.harness.reloadSession(sessionId);
8743
8779
  const restart_warnings = hookResult?.restart_warnings;
8744
- const diagnostics = hookResult?.diagnostics;
8780
+ const diagnostics = [
8781
+ ...hookResult?.diagnostics ?? [],
8782
+ ...(opts.harness.getResourceDiagnostics?.(sessionId) ?? []).map((d) => ({
8783
+ source: d.source,
8784
+ // The harness already folds the path into the message.
8785
+ message: d.message
8786
+ }))
8787
+ ];
8788
+ if (!reloaded) {
8789
+ diagnostics.push({
8790
+ source: "reload",
8791
+ message: "No live agent session to reload yet \u2014 changes apply to the next session."
8792
+ });
8793
+ }
8794
+ opts.onDiagnostics?.(diagnostics);
8745
8795
  return {
8746
8796
  ok: true,
8747
8797
  sessionId,
8748
8798
  reloaded,
8749
8799
  ...restart_warnings && restart_warnings.length > 0 ? { restart_warnings } : {},
8750
- ...diagnostics && diagnostics.length > 0 ? { diagnostics } : {}
8800
+ ...diagnostics.length > 0 ? { diagnostics } : {}
8751
8801
  };
8752
8802
  } catch (error) {
8753
8803
  const message = error instanceof Error ? error.message : String(error);
@@ -10402,6 +10452,41 @@ function toSessionCtx(ctx) {
10402
10452
  return { workspaceId: ctx.workspaceId, userId: ctx.authSubject };
10403
10453
  }
10404
10454
 
10455
+ // src/server/tools/pluginDiagnostics.ts
10456
+ function createPluginDiagnosticsTool(deps) {
10457
+ return {
10458
+ name: "plugin_diagnostics",
10459
+ description: [
10460
+ "Return current plugin/skill loading errors plus the diagnostics from the",
10461
+ "last /reload. Call this after asking the user to run /reload \u2014 or whenever a",
10462
+ "plugin or skill you expected does not appear to be loaded \u2014 then fix the",
10463
+ "reported error and ask the user to /reload again. Returns a JSON object with",
10464
+ "lastReloadDiagnostics, resourceDiagnostics, and pluginErrors arrays; an empty",
10465
+ "result means no load errors were detected."
10466
+ ].join(" "),
10467
+ parameters: {
10468
+ type: "object",
10469
+ properties: {},
10470
+ additionalProperties: false
10471
+ },
10472
+ async execute(_params, ctx) {
10473
+ const harness = deps.getHarness();
10474
+ const resourceDiagnostics = harness?.getResourceDiagnostics?.(ctx.sessionId ?? "") ?? [];
10475
+ const pluginErrors = deps.getPluginErrors ? await deps.getPluginErrors() : [];
10476
+ const payload = {
10477
+ lastReloadDiagnostics: deps.getLastReloadDiagnostics(),
10478
+ resourceDiagnostics,
10479
+ pluginErrors
10480
+ };
10481
+ return {
10482
+ content: [{ type: "text", text: JSON.stringify(payload) }],
10483
+ details: payload,
10484
+ isError: false
10485
+ };
10486
+ }
10487
+ };
10488
+ }
10489
+
10405
10490
  // src/server/createAgentApp.ts
10406
10491
  var DEFAULT_VERSION = "0.1.0-dev";
10407
10492
  var DEFAULT_SESSION_ID = "default";
@@ -10437,6 +10522,8 @@ async function createAgentApp(opts = {}) {
10437
10522
  ...opts.pi?.additionalSkillPaths ?? []
10438
10523
  ]
10439
10524
  };
10525
+ let harnessRef;
10526
+ let lastReloadDiagnostics = [];
10440
10527
  const tools = [
10441
10528
  ...buildHarnessAgentTools(runtimeBundle, {
10442
10529
  getCurrent: () => {
@@ -10446,7 +10533,14 @@ async function createAgentApp(opts = {}) {
10446
10533
  }),
10447
10534
  ...opts.disableDefaultFileTools ? [] : buildFilesystemAgentTools(runtimeBundle),
10448
10535
  ...opts.extraTools ?? [],
10449
- ...pluginTools
10536
+ ...pluginTools,
10537
+ createPluginDiagnosticsTool({
10538
+ getLastReloadDiagnostics: () => lastReloadDiagnostics,
10539
+ getHarness: () => harnessRef,
10540
+ ...opts.getPluginDiagnostics ? {
10541
+ getPluginErrors: () => opts.getPluginDiagnostics({ workspaceId: sessionId, workspaceRoot })
10542
+ } : {}
10543
+ })
10450
10544
  ];
10451
10545
  const harnessFactory = opts.harnessFactory ?? ((input) => createPiCodingAgentHarness({
10452
10546
  ...input,
@@ -10465,6 +10559,7 @@ async function createAgentApp(opts = {}) {
10465
10559
  systemPromptDynamic: opts.systemPromptDynamic,
10466
10560
  telemetry: opts.telemetry
10467
10561
  });
10562
+ harnessRef = harness;
10468
10563
  const sessionChangesTracker = new InMemorySessionChangesTracker();
10469
10564
  const readyTracker = new ReadyStatusTracker({
10470
10565
  sandboxReady: resolvedMode !== "vercel-sandbox",
@@ -10515,7 +10610,14 @@ async function createAgentApp(opts = {}) {
10515
10610
  await app.register(sessionChangesRoutes, { tracker: sessionChangesTracker });
10516
10611
  await app.register(catalogRoutes, { tools });
10517
10612
  await app.register(commandsRoutes, { harness, defaultSessionId: sessionId, workdir: runtimeBundle.workspace.root });
10518
- await app.register(reloadRoutes, { harness, defaultSessionId: sessionId, beforeReload: opts.beforeReload });
10613
+ await app.register(reloadRoutes, {
10614
+ harness,
10615
+ defaultSessionId: sessionId,
10616
+ beforeReload: opts.beforeReload,
10617
+ onDiagnostics: (diagnostics) => {
10618
+ lastReloadDiagnostics = diagnostics;
10619
+ }
10620
+ });
10519
10621
  await app.register(readyStatusRoutes, { tracker: readyTracker });
10520
10622
  return app;
10521
10623
  }
@@ -10984,7 +11086,15 @@ var registerAgentRoutes = async (app, opts) => {
10984
11086
  getReadiness: () => checkReadiness("runtime:python", {})
10985
11087
  }),
10986
11088
  ...buildFilesystemAgentTools(runtimeBundle),
10987
- ...buildUploadAgentTools(runtimeBundle)
11089
+ ...buildUploadAgentTools(runtimeBundle),
11090
+ createPluginDiagnosticsTool({
11091
+ // `binding` is assigned later in this function; read through thunks.
11092
+ getLastReloadDiagnostics: () => binding?.lastReloadDiagnostics ?? [],
11093
+ getHarness: () => binding?.harness,
11094
+ ...opts.getPluginDiagnostics ? {
11095
+ getPluginErrors: () => opts.getPluginDiagnostics({ workspaceId, workspaceRoot: root })
11096
+ } : {}
11097
+ })
10988
11098
  ];
10989
11099
  const pluginTools = [];
10990
11100
  if (modeAdapter.workspaceFsCapability === "strong") {
@@ -11302,13 +11412,28 @@ var registerAgentRoutes = async (app, opts) => {
11302
11412
  const reloadSessionId = request.body?.sessionId || sessionId;
11303
11413
  const reloaded = await binding.harness.reloadSession(reloadSessionId);
11304
11414
  const restart_warnings = hookResult?.restart_warnings;
11305
- const diagnostics = hookResult?.diagnostics;
11415
+ const diagnostics = [
11416
+ ...hookResult?.diagnostics ?? [],
11417
+ ...(binding.harness.getResourceDiagnostics?.(reloadSessionId) ?? []).map((d) => ({
11418
+ source: d.source,
11419
+ // The harness already folds the path into the message (front only
11420
+ // renders `.message`).
11421
+ message: d.message
11422
+ }))
11423
+ ];
11424
+ if (!reloaded) {
11425
+ diagnostics.push({
11426
+ source: "reload",
11427
+ message: "No live agent session to reload yet \u2014 changes apply to the next session."
11428
+ });
11429
+ }
11430
+ binding.lastReloadDiagnostics = diagnostics;
11306
11431
  return {
11307
11432
  ok: true,
11308
11433
  sessionId: reloadSessionId,
11309
11434
  reloaded,
11310
11435
  ...restart_warnings && restart_warnings.length > 0 ? { restart_warnings } : {},
11311
- ...diagnostics && diagnostics.length > 0 ? { diagnostics } : {}
11436
+ ...diagnostics.length > 0 ? { diagnostics } : {}
11312
11437
  };
11313
11438
  } catch (error) {
11314
11439
  const message = error instanceof Error ? error.message : String(error);
@@ -1,5 +1,5 @@
1
- import { W as Workspace, S as Sandbox, F as FileSearch, A as AgentTool } from '../agentPluginEvents-DgNc3erX.js';
2
- export { a as AgentHarness, C as CommandNotifyPayload, E as Entry, b as ExecOptions, c as ExecResult, I as IsolatedCodeInput, d as IsolatedCodeOutput, J as JSONSchema, R as RunContext, e as SandboxCapability, f as SandboxHandleRecord, g as SandboxHandleStore, h as SendMessageInput, i as Stat, T as TelemetryEvent, j as TelemetrySink, k as ToolExecContext, l as ToolResult, m as WORKSPACE_AGENT_PLUGINS_RELOADED_EVENT, n as WORKSPACE_COMMAND_NOTIFY_EVENT, o as WorkspaceRuntimeContext, p as noopTelemetry, s as safeCapture } from '../agentPluginEvents-DgNc3erX.js';
1
+ import { W as Workspace, S as Sandbox, F as FileSearch, A as AgentTool } from '../agentPluginEvents-CKrZLW3g.js';
2
+ export { a as AgentHarness, C as CommandNotifyPayload, E as Entry, b as ExecOptions, c as ExecResult, I as IsolatedCodeInput, d as IsolatedCodeOutput, J as JSONSchema, R as RunContext, e as SandboxCapability, f as SandboxHandleRecord, g as SandboxHandleStore, h as SendMessageInput, i as Stat, T as TelemetryEvent, j as TelemetrySink, k as ToolExecContext, l as ToolResult, m as WORKSPACE_AGENT_PLUGINS_RELOADED_EVENT, n as WORKSPACE_COMMAND_NOTIFY_EVENT, o as WorkspaceRuntimeContext, p as noopTelemetry, s as safeCapture } from '../agentPluginEvents-CKrZLW3g.js';
3
3
  import { B as BoringChatPart, T as ToolUiMetadata } from '../piChatEvent-Ck1BAE_m.js';
4
4
  export { A as ApiErrorPayload, a as ApiErrorPayloadSchema, b as ApiErrorResponse, c as ApiErrorResponseSchema, d as BoringChatMessage, C as ChatAttachmentPayload, e as ChatError, f as ChatModelSelection, g as ChatSubmitPayload, h as CommandReceipt, E as ERROR_CODES, i as ErrorCode, j as ErrorLogFields, k as ErrorLogFieldsSchema, F as FollowUpPayload, l as FollowUpReceipt, I as InterruptPayload, m as InterruptReceipt, P as PiChatEvent, n as PiChatHeartbeatFrame, o as PiChatSnapshot, p as PiChatStatus, q as PiChatStreamFrame, r as PromptPayload, s as PromptReceipt, Q as QueueClearPayload, t as QueueClearReceipt, u as QueuedUserMessage, S as StopPayload, v as StopReceipt, w as ThinkingLevel, x as extractToolUiMetadata, y as isToolUiMetadata } from '../piChatEvent-Ck1BAE_m.js';
5
5
  export { S as SessionCtx, a as SessionDetail, b as SessionStore, c as SessionSummary } from '../session-BRovhe0D.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hachej/boring-agent",
3
- "version": "0.1.37",
3
+ "version": "0.1.39",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Pane-embeddable coding agent. Ships direct/local/vercel-sandbox execution modes behind one interface.",
@@ -74,7 +74,7 @@
74
74
  "use-stick-to-bottom": "^1.1.3",
75
75
  "yaml": "^2.8.3",
76
76
  "zod": "^3.25.76",
77
- "@hachej/boring-ui-kit": "0.1.37"
77
+ "@hachej/boring-ui-kit": "0.1.39"
78
78
  },
79
79
  "devDependencies": {
80
80
  "@antithesishq/bombadil": "0.5.0",