@hachej/boring-agent 0.1.35 → 0.1.36

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.
@@ -260,6 +260,9 @@
260
260
  .inline-flex {
261
261
  display: inline-flex;
262
262
  }
263
+ .table {
264
+ display: table;
265
+ }
263
266
  .\[field-sizing\:fixed\] {
264
267
  field-sizing: fixed;
265
268
  }
@@ -377,6 +380,9 @@
377
380
  .max-h-48 {
378
381
  max-height: calc(var(--spacing) * 48);
379
382
  }
383
+ .max-h-80 {
384
+ max-height: calc(var(--spacing) * 80);
385
+ }
380
386
  .max-h-\[45vh\] {
381
387
  max-height: 45vh;
382
388
  }
@@ -865,6 +871,12 @@
865
871
  border-color: color-mix(in oklab, var(--destructive) 30%, transparent);
866
872
  }
867
873
  }
874
+ .border-destructive\/40 {
875
+ border-color: var(--destructive);
876
+ @supports (color: color-mix(in lab, red, red)) {
877
+ border-color: color-mix(in oklab, var(--destructive) 40%, transparent);
878
+ }
879
+ }
868
880
  .border-input\/40 {
869
881
  border-color: var(--input);
870
882
  @supports (color: color-mix(in lab, red, red)) {
@@ -991,6 +1003,12 @@
991
1003
  background-color: color-mix(in oklab, var(--accent) 10%, transparent);
992
1004
  }
993
1005
  }
1006
+ .bg-accent\/15 {
1007
+ background-color: var(--accent);
1008
+ @supports (color: color-mix(in lab, red, red)) {
1009
+ background-color: color-mix(in oklab, var(--accent) 15%, transparent);
1010
+ }
1011
+ }
994
1012
  .bg-amber-500\/70 {
995
1013
  background-color: color-mix(in srgb, oklch(76.9% 0.188 70.08) 70%, transparent);
996
1014
  @supports (color: color-mix(in lab, red, red)) {
@@ -1297,6 +1315,9 @@
1297
1315
  .py-\[0\.08em\] {
1298
1316
  padding-block: 0.08em;
1299
1317
  }
1318
+ .py-px {
1319
+ padding-block: 1px;
1320
+ }
1300
1321
  .pt-0 {
1301
1322
  padding-top: calc(var(--spacing) * 0);
1302
1323
  }
@@ -1375,6 +1396,9 @@
1375
1396
  .text-\[0\.8125rem\] {
1376
1397
  font-size: 0.8125rem;
1377
1398
  }
1399
+ .text-\[9px\] {
1400
+ font-size: 9px;
1401
+ }
1378
1402
  .text-\[10\.5px\] {
1379
1403
  font-size: 10.5px;
1380
1404
  }
@@ -1548,6 +1572,9 @@
1548
1572
  .text-accent {
1549
1573
  color: var(--accent);
1550
1574
  }
1575
+ .text-accent-foreground {
1576
+ color: var(--accent-foreground);
1577
+ }
1551
1578
  .text-accent\/80 {
1552
1579
  color: var(--accent);
1553
1580
  @supports (color: color-mix(in lab, red, red)) {
@@ -1,5 +1,5 @@
1
- import { n 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, p as AgentHarnessFactory } from '../agentPluginEvents-CAMp363h.js';
2
- export { q as AgentHarnessFactoryInput } from '../agentPluginEvents-CAMp363h.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-DgNc3erX.js';
2
+ export { r as AgentHarnessFactoryInput } from '../agentPluginEvents-DgNc3erX.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';
@@ -6377,6 +6377,29 @@ async function applyRequestedSessionOptions(handle, input) {
6377
6377
  }
6378
6378
  }
6379
6379
  var log3 = createLogger("pi-harness");
6380
+ function deriveSourcePlugin(sourceInfo) {
6381
+ if (!sourceInfo) return void 0;
6382
+ const path4 = typeof sourceInfo.path === "string" ? sourceInfo.path : "";
6383
+ const source = typeof sourceInfo.source === "string" ? sourceInfo.source : "";
6384
+ const runtimePlugin = path4.match(/[/\\]\.pi[/\\]extensions[/\\]([^/\\]+)/);
6385
+ if (runtimePlugin) return runtimePlugin[1];
6386
+ const provisionedSkill = path4.match(/[/\\]\.boring-agent[/\\]skills[/\\]([^/\\]+)/);
6387
+ if (provisionedSkill) return provisionedSkill[1];
6388
+ if (source.startsWith("npm:")) return source.slice(4) || void 0;
6389
+ if (source.startsWith("git/")) return source.split("/").filter(Boolean).pop();
6390
+ const fileExtension = path4.match(/[/\\]extensions[/\\]([^/\\]+)\.[cm]?[tj]sx?$/);
6391
+ if (fileExtension) return fileExtension[1];
6392
+ return void 0;
6393
+ }
6394
+ function normalizeSlashCommandInfo(command) {
6395
+ const sourcePlugin = deriveSourcePlugin(command.sourceInfo);
6396
+ return {
6397
+ name: command.name,
6398
+ ...command.description ? { description: command.description } : {},
6399
+ source: command.source,
6400
+ ...sourcePlugin ? { sourcePlugin } : {}
6401
+ };
6402
+ }
6380
6403
  function createPiCodingAgentHarness(opts) {
6381
6404
  const sessionStore = new PiSessionStore(opts.runtimeCwd ?? opts.cwd, {
6382
6405
  sessionNamespace: opts.sessionNamespace,
@@ -6499,7 +6522,7 @@ function createPiCodingAgentHarness(opts) {
6499
6522
  });
6500
6523
  }
6501
6524
  }
6502
- const handle = { piSession, modelRegistry, sessionManager };
6525
+ const handle = { piSession, modelRegistry, sessionManager, resourceLoader };
6503
6526
  piSessions.set(sessionId, handle);
6504
6527
  return handle;
6505
6528
  }
@@ -6538,6 +6561,22 @@ function createPiCodingAgentHarness(opts) {
6538
6561
  return piSessions.has(sessionId);
6539
6562
  },
6540
6563
  reloadSession: reloadPiSession,
6564
+ async getSlashCommands(sessionId, ctx) {
6565
+ const handle = await getOrCreatePiSession(sessionId, { sessionId, message: "" }, ctx);
6566
+ return handle.resourceLoader.getExtensions().runtime.getCommands().map(normalizeSlashCommandInfo);
6567
+ },
6568
+ async executeSlashCommand(sessionId, name, args, ctx) {
6569
+ const handle = await getOrCreatePiSession(sessionId, { sessionId, message: "" }, ctx);
6570
+ const command = handle.piSession.extensionRunner.getCommand(name);
6571
+ if (command) {
6572
+ await command.handler(args, handle.piSession.extensionRunner.createCommandContext());
6573
+ return;
6574
+ }
6575
+ const knownCommand = handle.resourceLoader.getExtensions().runtime.getCommands().some((candidate) => candidate.name === name);
6576
+ if (!knownCommand) throw new Error(`command '${name}' not registered in session '${sessionId}'`);
6577
+ const text = args.trim() ? `/${name} ${args}` : `/${name}`;
6578
+ await handle.piSession.prompt(text);
6579
+ },
6541
6580
  async getPiSessionAdapter(input, ctx) {
6542
6581
  const { piSession } = await getOrCreatePiSession(input.sessionId, input, ctx);
6543
6582
  return createPiAgentSessionAdapter(piSession, {
@@ -8642,6 +8681,51 @@ data: ${JSON.stringify(event)}
8642
8681
  done();
8643
8682
  }
8644
8683
 
8684
+ // src/server/http/routes/commands.ts
8685
+ function normalizeSessionId(value, fallback) {
8686
+ if (typeof value !== "string") return fallback;
8687
+ const trimmed = value.trim();
8688
+ return trimmed.length > 0 ? trimmed : fallback;
8689
+ }
8690
+ function commandsRoutes(app, opts, done) {
8691
+ app.get("/api/v1/agent/commands", async (request, reply) => {
8692
+ try {
8693
+ const query = request.query;
8694
+ const sessionId = normalizeSessionId(query.sessionId, opts.defaultSessionId);
8695
+ const commands = await opts.harness.getSlashCommands?.(sessionId, {
8696
+ abortSignal: new AbortController().signal,
8697
+ workdir: opts.workdir
8698
+ }) ?? [];
8699
+ return reply.code(200).send({ commands });
8700
+ } catch (error) {
8701
+ const message = error instanceof Error ? error.message : String(error);
8702
+ return reply.code(500).send({ commands: [], error: message });
8703
+ }
8704
+ });
8705
+ app.post("/api/v1/agent/commands/execute", async (request, reply) => {
8706
+ if (!opts.harness.executeSlashCommand) {
8707
+ return reply.code(501).send({ error: "Command execution not supported by this harness." });
8708
+ }
8709
+ try {
8710
+ const query = request.query;
8711
+ const body = request.body && typeof request.body === "object" ? request.body : {};
8712
+ const sessionId = normalizeSessionId(query.sessionId, opts.defaultSessionId);
8713
+ const name = typeof body.name === "string" ? body.name.trim() : "";
8714
+ const args = typeof body.args === "string" ? body.args : "";
8715
+ if (!name) return reply.code(400).send({ error: "name body field is required" });
8716
+ await opts.harness.executeSlashCommand(sessionId, name, args, {
8717
+ abortSignal: new AbortController().signal,
8718
+ workdir: opts.workdir
8719
+ });
8720
+ return reply.code(200).send({ ok: true });
8721
+ } catch (error) {
8722
+ const message = error instanceof Error ? error.message : String(error);
8723
+ return reply.code(500).send({ error: message });
8724
+ }
8725
+ });
8726
+ done();
8727
+ }
8728
+
8645
8729
  // src/server/http/routes/reload.ts
8646
8730
  function reloadRoutes(app, opts, done) {
8647
8731
  app.post("/api/v1/agent/reload", async (request, reply) => {
@@ -8746,12 +8830,25 @@ function normalizeRemoteUrl(remoteUrl) {
8746
8830
  if (sshMatch) {
8747
8831
  return `https://github.com/${sshMatch[1]}/${sshMatch[2]}`;
8748
8832
  }
8749
- const httpsMatch = /^https:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?\/?$/i.exec(trimmed);
8750
- if (httpsMatch) {
8751
- return `https://github.com/${httpsMatch[1]}/${httpsMatch[2]}`;
8752
- }
8833
+ const httpsBaseUrl = normalizeHttpsGithubRemote(trimmed);
8834
+ if (httpsBaseUrl) return httpsBaseUrl;
8753
8835
  return null;
8754
8836
  }
8837
+ function normalizeHttpsGithubRemote(remoteUrl) {
8838
+ let url;
8839
+ try {
8840
+ url = new URL(remoteUrl);
8841
+ } catch {
8842
+ return null;
8843
+ }
8844
+ if (url.protocol !== "https:" || url.hostname.toLowerCase() !== "github.com") return null;
8845
+ const parts = url.pathname.replace(/^\/+|\/+$/g, "").split("/");
8846
+ if (parts.length !== 2) return null;
8847
+ const [owner, repoWithSuffix] = parts;
8848
+ const repo = repoWithSuffix.endsWith(".git") ? repoWithSuffix.slice(0, -4) : repoWithSuffix;
8849
+ if (!owner || !repo) return null;
8850
+ return `https://github.com/${owner}/${repo}`;
8851
+ }
8755
8852
  function sanitizeRef(value) {
8756
8853
  return typeof value === "string" && value.trim() ? value.trim() : null;
8757
8854
  }
@@ -10413,6 +10510,7 @@ async function createAgentApp(opts = {}) {
10413
10510
  });
10414
10511
  await app.register(sessionChangesRoutes, { tracker: sessionChangesTracker });
10415
10512
  await app.register(catalogRoutes, { tools });
10513
+ await app.register(commandsRoutes, { harness, defaultSessionId: sessionId, workdir: runtimeBundle.workspace.root });
10416
10514
  await app.register(reloadRoutes, { harness, defaultSessionId: sessionId, beforeReload: opts.beforeReload });
10417
10515
  await app.register(readyStatusRoutes, { tracker: readyTracker });
10418
10516
  return app;
@@ -1,5 +1,5 @@
1
- import { W as Workspace, S as Sandbox, F as FileSearch, A as AgentTool } from '../agentPluginEvents-CAMp363h.js';
2
- export { a as AgentHarness, 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 WorkspaceRuntimeContext, o as noopTelemetry, s as safeCapture } from '../agentPluginEvents-CAMp363h.js';
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';
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';
@@ -807,15 +807,15 @@ declare const PiChatEventSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
807
807
  finalError: z.ZodOptional<z.ZodString>;
808
808
  }, "strip", z.ZodTypeAny, {
809
809
  type: "auto-retry-end";
810
+ success: boolean;
810
811
  seq: number;
811
812
  attempt: number;
812
- success: boolean;
813
813
  finalError?: string | undefined;
814
814
  }, {
815
815
  type: "auto-retry-end";
816
+ success: boolean;
816
817
  seq: number;
817
818
  attempt: number;
818
- success: boolean;
819
819
  finalError?: string | undefined;
820
820
  }>, z.ZodObject<{
821
821
  seq: z.ZodNumber;
@@ -1262,15 +1262,15 @@ declare const PiChatStreamFrameSchema: z.ZodUnion<[z.ZodDiscriminatedUnion<"type
1262
1262
  finalError: z.ZodOptional<z.ZodString>;
1263
1263
  }, "strip", z.ZodTypeAny, {
1264
1264
  type: "auto-retry-end";
1265
+ success: boolean;
1265
1266
  seq: number;
1266
1267
  attempt: number;
1267
- success: boolean;
1268
1268
  finalError?: string | undefined;
1269
1269
  }, {
1270
1270
  type: "auto-retry-end";
1271
+ success: boolean;
1271
1272
  seq: number;
1272
1273
  attempt: number;
1273
- success: boolean;
1274
1274
  finalError?: string | undefined;
1275
1275
  }>, z.ZodObject<{
1276
1276
  seq: z.ZodNumber;
@@ -4,8 +4,9 @@ import {
4
4
  validateTool
5
5
  } from "../chunk-HDOSWEXG.js";
6
6
  import {
7
- WORKSPACE_AGENT_PLUGINS_RELOADED_EVENT
8
- } from "../chunk-NZN2PRET.js";
7
+ WORKSPACE_AGENT_PLUGINS_RELOADED_EVENT,
8
+ WORKSPACE_COMMAND_NOTIFY_EVENT
9
+ } from "../chunk-DGRKMMXO.js";
9
10
  import {
10
11
  ApiErrorPayloadSchema,
11
12
  ApiErrorResponseSchema,
@@ -138,6 +139,7 @@ export {
138
139
  ThinkingLevelSchema,
139
140
  ToolUiMetadataSchema,
140
141
  WORKSPACE_AGENT_PLUGINS_RELOADED_EVENT,
142
+ WORKSPACE_COMMAND_NOTIFY_EVENT,
141
143
  extractToolUiMetadata,
142
144
  isToolUiMetadata,
143
145
  noopTelemetry,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hachej/boring-agent",
3
- "version": "0.1.35",
3
+ "version": "0.1.36",
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.35"
77
+ "@hachej/boring-ui-kit": "0.1.36"
78
78
  },
79
79
  "devDependencies": {
80
80
  "@antithesishq/bombadil": "0.5.0",
@@ -1,6 +0,0 @@
1
- // src/shared/agentPluginEvents.ts
2
- var WORKSPACE_AGENT_PLUGINS_RELOADED_EVENT = "boring-ui:agent-plugins-reloaded";
3
-
4
- export {
5
- WORKSPACE_AGENT_PLUGINS_RELOADED_EVENT
6
- };