@hachej/boring-agent 0.1.35 → 0.1.37

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';
@@ -433,13 +433,17 @@ var DEFAULT_WATCH_IGNORES = [
433
433
  "node_modules",
434
434
  ".git",
435
435
  ".DS_Store",
436
+ ".worktrees",
437
+ ".boring-agent",
438
+ ".cache",
436
439
  "dist",
437
440
  ".next",
438
441
  ".turbo",
439
442
  "test-results"
440
443
  ];
441
- function shouldIgnoreWatchPath(path4) {
442
- const parts = path4.split(sep);
444
+ function shouldIgnoreWatchPath(root, path4) {
445
+ const relPath = relative2(root, path4);
446
+ const parts = relPath.split(sep);
443
447
  return parts.some(
444
448
  (part) => DEFAULT_WATCH_IGNORES.includes(part) || part.endsWith(".tsbuildinfo")
445
449
  );
@@ -451,7 +455,7 @@ function createNodeWatcher(root) {
451
455
  const ensureFsw = () => {
452
456
  if (fsw) return fsw;
453
457
  fsw = chokidar.watch(root, {
454
- ignored: shouldIgnoreWatchPath,
458
+ ignored: (path4) => shouldIgnoreWatchPath(root, path4),
455
459
  ignoreInitial: true,
456
460
  persistent: true,
457
461
  followSymlinks: false
@@ -6377,6 +6381,29 @@ async function applyRequestedSessionOptions(handle, input) {
6377
6381
  }
6378
6382
  }
6379
6383
  var log3 = createLogger("pi-harness");
6384
+ function deriveSourcePlugin(sourceInfo) {
6385
+ if (!sourceInfo) return void 0;
6386
+ const path4 = typeof sourceInfo.path === "string" ? sourceInfo.path : "";
6387
+ const source = typeof sourceInfo.source === "string" ? sourceInfo.source : "";
6388
+ const runtimePlugin = path4.match(/[/\\]\.pi[/\\]extensions[/\\]([^/\\]+)/);
6389
+ if (runtimePlugin) return runtimePlugin[1];
6390
+ const provisionedSkill = path4.match(/[/\\]\.boring-agent[/\\]skills[/\\]([^/\\]+)/);
6391
+ if (provisionedSkill) return provisionedSkill[1];
6392
+ if (source.startsWith("npm:")) return source.slice(4) || void 0;
6393
+ if (source.startsWith("git/")) return source.split("/").filter(Boolean).pop();
6394
+ const fileExtension = path4.match(/[/\\]extensions[/\\]([^/\\]+)\.[cm]?[tj]sx?$/);
6395
+ if (fileExtension) return fileExtension[1];
6396
+ return void 0;
6397
+ }
6398
+ function normalizeSlashCommandInfo(command) {
6399
+ const sourcePlugin = deriveSourcePlugin(command.sourceInfo);
6400
+ return {
6401
+ name: command.name,
6402
+ ...command.description ? { description: command.description } : {},
6403
+ source: command.source,
6404
+ ...sourcePlugin ? { sourcePlugin } : {}
6405
+ };
6406
+ }
6380
6407
  function createPiCodingAgentHarness(opts) {
6381
6408
  const sessionStore = new PiSessionStore(opts.runtimeCwd ?? opts.cwd, {
6382
6409
  sessionNamespace: opts.sessionNamespace,
@@ -6499,7 +6526,7 @@ function createPiCodingAgentHarness(opts) {
6499
6526
  });
6500
6527
  }
6501
6528
  }
6502
- const handle = { piSession, modelRegistry, sessionManager };
6529
+ const handle = { piSession, modelRegistry, sessionManager, resourceLoader };
6503
6530
  piSessions.set(sessionId, handle);
6504
6531
  return handle;
6505
6532
  }
@@ -6538,6 +6565,22 @@ function createPiCodingAgentHarness(opts) {
6538
6565
  return piSessions.has(sessionId);
6539
6566
  },
6540
6567
  reloadSession: reloadPiSession,
6568
+ async getSlashCommands(sessionId, ctx) {
6569
+ const handle = await getOrCreatePiSession(sessionId, { sessionId, message: "" }, ctx);
6570
+ return handle.resourceLoader.getExtensions().runtime.getCommands().map(normalizeSlashCommandInfo);
6571
+ },
6572
+ async executeSlashCommand(sessionId, name, args, ctx) {
6573
+ const handle = await getOrCreatePiSession(sessionId, { sessionId, message: "" }, ctx);
6574
+ const command = handle.piSession.extensionRunner.getCommand(name);
6575
+ if (command) {
6576
+ await command.handler(args, handle.piSession.extensionRunner.createCommandContext());
6577
+ return;
6578
+ }
6579
+ const knownCommand = handle.resourceLoader.getExtensions().runtime.getCommands().some((candidate) => candidate.name === name);
6580
+ if (!knownCommand) throw new Error(`command '${name}' not registered in session '${sessionId}'`);
6581
+ const text = args.trim() ? `/${name} ${args}` : `/${name}`;
6582
+ await handle.piSession.prompt(text);
6583
+ },
6541
6584
  async getPiSessionAdapter(input, ctx) {
6542
6585
  const { piSession } = await getOrCreatePiSession(input.sessionId, input, ctx);
6543
6586
  return createPiAgentSessionAdapter(piSession, {
@@ -8642,6 +8685,51 @@ data: ${JSON.stringify(event)}
8642
8685
  done();
8643
8686
  }
8644
8687
 
8688
+ // src/server/http/routes/commands.ts
8689
+ function normalizeSessionId(value, fallback) {
8690
+ if (typeof value !== "string") return fallback;
8691
+ const trimmed = value.trim();
8692
+ return trimmed.length > 0 ? trimmed : fallback;
8693
+ }
8694
+ function commandsRoutes(app, opts, done) {
8695
+ app.get("/api/v1/agent/commands", async (request, reply) => {
8696
+ try {
8697
+ const query = request.query;
8698
+ const sessionId = normalizeSessionId(query.sessionId, opts.defaultSessionId);
8699
+ const commands = await opts.harness.getSlashCommands?.(sessionId, {
8700
+ abortSignal: new AbortController().signal,
8701
+ workdir: opts.workdir
8702
+ }) ?? [];
8703
+ return reply.code(200).send({ commands });
8704
+ } catch (error) {
8705
+ const message = error instanceof Error ? error.message : String(error);
8706
+ return reply.code(500).send({ commands: [], error: message });
8707
+ }
8708
+ });
8709
+ app.post("/api/v1/agent/commands/execute", async (request, reply) => {
8710
+ if (!opts.harness.executeSlashCommand) {
8711
+ return reply.code(501).send({ error: "Command execution not supported by this harness." });
8712
+ }
8713
+ try {
8714
+ const query = request.query;
8715
+ const body = request.body && typeof request.body === "object" ? request.body : {};
8716
+ const sessionId = normalizeSessionId(query.sessionId, opts.defaultSessionId);
8717
+ const name = typeof body.name === "string" ? body.name.trim() : "";
8718
+ const args = typeof body.args === "string" ? body.args : "";
8719
+ if (!name) return reply.code(400).send({ error: "name body field is required" });
8720
+ await opts.harness.executeSlashCommand(sessionId, name, args, {
8721
+ abortSignal: new AbortController().signal,
8722
+ workdir: opts.workdir
8723
+ });
8724
+ return reply.code(200).send({ ok: true });
8725
+ } catch (error) {
8726
+ const message = error instanceof Error ? error.message : String(error);
8727
+ return reply.code(500).send({ error: message });
8728
+ }
8729
+ });
8730
+ done();
8731
+ }
8732
+
8645
8733
  // src/server/http/routes/reload.ts
8646
8734
  function reloadRoutes(app, opts, done) {
8647
8735
  app.post("/api/v1/agent/reload", async (request, reply) => {
@@ -8746,12 +8834,25 @@ function normalizeRemoteUrl(remoteUrl) {
8746
8834
  if (sshMatch) {
8747
8835
  return `https://github.com/${sshMatch[1]}/${sshMatch[2]}`;
8748
8836
  }
8749
- const httpsMatch = /^https:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?\/?$/i.exec(trimmed);
8750
- if (httpsMatch) {
8751
- return `https://github.com/${httpsMatch[1]}/${httpsMatch[2]}`;
8752
- }
8837
+ const httpsBaseUrl = normalizeHttpsGithubRemote(trimmed);
8838
+ if (httpsBaseUrl) return httpsBaseUrl;
8753
8839
  return null;
8754
8840
  }
8841
+ function normalizeHttpsGithubRemote(remoteUrl) {
8842
+ let url;
8843
+ try {
8844
+ url = new URL(remoteUrl);
8845
+ } catch {
8846
+ return null;
8847
+ }
8848
+ if (url.protocol !== "https:" || url.hostname.toLowerCase() !== "github.com") return null;
8849
+ const parts = url.pathname.replace(/^\/+|\/+$/g, "").split("/");
8850
+ if (parts.length !== 2) return null;
8851
+ const [owner, repoWithSuffix] = parts;
8852
+ const repo = repoWithSuffix.endsWith(".git") ? repoWithSuffix.slice(0, -4) : repoWithSuffix;
8853
+ if (!owner || !repo) return null;
8854
+ return `https://github.com/${owner}/${repo}`;
8855
+ }
8755
8856
  function sanitizeRef(value) {
8756
8857
  return typeof value === "string" && value.trim() ? value.trim() : null;
8757
8858
  }
@@ -10413,6 +10514,7 @@ async function createAgentApp(opts = {}) {
10413
10514
  });
10414
10515
  await app.register(sessionChangesRoutes, { tracker: sessionChangesTracker });
10415
10516
  await app.register(catalogRoutes, { tools });
10517
+ await app.register(commandsRoutes, { harness, defaultSessionId: sessionId, workdir: runtimeBundle.workspace.root });
10416
10518
  await app.register(reloadRoutes, { harness, defaultSessionId: sessionId, beforeReload: opts.beforeReload });
10417
10519
  await app.register(readyStatusRoutes, { tracker: readyTracker });
10418
10520
  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.37",
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.37"
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
- };