@h-rig/cli 0.0.6-alpha.41 → 0.0.6-alpha.43

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/src/index.js CHANGED
@@ -3205,6 +3205,10 @@ async function getRunPiCommandsViaServer(context, runId) {
3205
3205
  const payload = await requestServerJson(context, `/api/runs/${encodeURIComponent(runId)}/pi/commands`);
3206
3206
  return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : { commands: [] };
3207
3207
  }
3208
+ async function getRunPiCapabilitiesViaServer(context, runId) {
3209
+ const payload = await requestServerJson(context, `/api/runs/${encodeURIComponent(runId)}/pi/capabilities`);
3210
+ return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : { capabilities: null };
3211
+ }
3208
3212
  async function sendRunPiPromptViaServer(context, runId, text2, streamingBehavior) {
3209
3213
  const payload = await requestServerJson(context, `/api/runs/${encodeURIComponent(runId)}/pi/prompt`, {
3210
3214
  method: "POST",
@@ -4444,7 +4448,7 @@ function formatSubmittedRun(input) {
4444
4448
  ...formatNextSteps([
4445
4449
  `Attach: \`rig run attach ${input.runId} --follow\``,
4446
4450
  `Inspect: \`rig run show ${input.runId}\``,
4447
- input.detached ? "Submitted detached; attach when you are ready." : "Interactive mode opens the native bundled Pi frontend."
4451
+ input.detached ? "Submitted detached; attach when you are ready." : "Interactive mode opens the enriched bundled Pi (native UI + Rig layers, worker brain)."
4448
4452
  ])
4449
4453
  ].join(`
4450
4454
  `);
@@ -7386,7 +7390,7 @@ import {
7386
7390
  } from "@earendil-works/pi-coding-agent";
7387
7391
 
7388
7392
  // packages/cli/src/commands/_pi-remote-session.ts
7389
- import { AgentSession as PiAgentSession } from "@earendil-works/pi-coding-agent";
7393
+ import { AgentSession as PiAgentSession, expandPromptTemplate } from "@earendil-works/pi-coding-agent";
7390
7394
  var TERMINAL_RUN_STATUSES = new Set(["completed", "failed", "stopped", "cancelled", "canceled", "closed", "merged", "needs_attention", "needs-attention"]);
7391
7395
  function defaultTransport() {
7392
7396
  return {
@@ -7394,6 +7398,7 @@ function defaultTransport() {
7394
7398
  getMessages: getRunPiMessagesViaServer,
7395
7399
  getStatus: getRunPiStatusViaServer,
7396
7400
  getCommands: getRunPiCommandsViaServer,
7401
+ getCapabilities: getRunPiCapabilitiesViaServer,
7397
7402
  sendPrompt: sendRunPiPromptViaServer,
7398
7403
  sendShell: sendRunPiShellViaServer,
7399
7404
  runCommand: runRunPiCommandViaServer,
@@ -7481,16 +7486,18 @@ class RigRemoteSessionController {
7481
7486
  this.hooks.onStatusText?.("worker Pi WebSocket disconnected");
7482
7487
  };
7483
7488
  try {
7484
- const [messagesPayload, statusPayload, commandsPayload] = await Promise.all([
7489
+ const [messagesPayload, statusPayload, commandsPayload, capabilitiesPayload] = await Promise.all([
7485
7490
  this.transport.getMessages(this.context, this.runId),
7486
7491
  this.transport.getStatus(this.context, this.runId),
7487
- this.transport.getCommands(this.context, this.runId)
7492
+ this.transport.getCommands(this.context, this.runId),
7493
+ this.transport.getCapabilities(this.context, this.runId).catch(() => ({ capabilities: null }))
7488
7494
  ]);
7489
7495
  const messages = Array.isArray(messagesPayload.messages) ? messagesPayload.messages : [];
7490
7496
  this.applyStatusPayload(statusPayload);
7491
7497
  this.session?.replaceRemoteMessages(messages);
7492
7498
  const commands = Array.isArray(commandsPayload.commands) ? commandsPayload.commands : [];
7493
- this.hooks.onCatchUp?.(messages, commands);
7499
+ const capabilities = capabilitiesPayload.capabilities && typeof capabilitiesPayload.capabilities === "object" && !Array.isArray(capabilitiesPayload.capabilities) ? capabilitiesPayload.capabilities : null;
7500
+ this.hooks.onCatchUp?.(messages, commands, capabilities);
7494
7501
  catchupDone = true;
7495
7502
  for (const payload of buffered.splice(0))
7496
7503
  this.applyEnvelope(payload);
@@ -7667,6 +7674,20 @@ class RigRemoteAgentSession extends PiAgentSession {
7667
7674
  replaceRemoteMessages(messages) {
7668
7675
  this.agent.state.messages = messages;
7669
7676
  }
7677
+ async expandLocalInput(text2) {
7678
+ let current = text2;
7679
+ const runner = this.extensionRunner;
7680
+ if (runner.hasHandlers("input")) {
7681
+ const result = await runner.emitInput(current, undefined, "interactive");
7682
+ if (result.action === "handled")
7683
+ return null;
7684
+ if (result.action === "transform")
7685
+ current = result.text;
7686
+ }
7687
+ current = this._expandSkillCommand(current);
7688
+ current = expandPromptTemplate(current, [...this.promptTemplates]);
7689
+ return current;
7690
+ }
7670
7691
  async prompt(text2, options) {
7671
7692
  const trimmed = text2.trim();
7672
7693
  if (!trimmed)
@@ -7674,6 +7695,15 @@ class RigRemoteAgentSession extends PiAgentSession {
7674
7695
  if (trimmed.startsWith("/")) {
7675
7696
  if (await this._tryExecuteExtensionCommand(trimmed))
7676
7697
  return;
7698
+ const expanded2 = await this.expandLocalInput(trimmed);
7699
+ if (expanded2 === null)
7700
+ return;
7701
+ if (expanded2 !== trimmed) {
7702
+ const behavior2 = options?.streamingBehavior ?? (this.isStreaming || this.isCompacting ? "steer" : undefined);
7703
+ options?.preflightResult?.(true);
7704
+ await this.remote.sendPrompt(expanded2, behavior2);
7705
+ return;
7706
+ }
7677
7707
  await this.remote.sendCommand(trimmed);
7678
7708
  return;
7679
7709
  }
@@ -7681,15 +7711,30 @@ class RigRemoteAgentSession extends PiAgentSession {
7681
7711
  await this.remote.sendShell(trimmed);
7682
7712
  return;
7683
7713
  }
7714
+ const expanded = await this.expandLocalInput(trimmed);
7715
+ if (expanded === null)
7716
+ return;
7684
7717
  const behavior = options?.streamingBehavior ?? (this.isStreaming || this.isCompacting ? "steer" : undefined);
7685
7718
  options?.preflightResult?.(true);
7686
- await this.remote.sendPrompt(trimmed, behavior);
7719
+ await this.remote.sendPrompt(expanded, behavior);
7687
7720
  }
7688
7721
  async steer(text2) {
7689
- await this.remote.sendPrompt(text2, "steer");
7722
+ const trimmed = text2.trim();
7723
+ if (trimmed.startsWith("/") && await this._tryExecuteExtensionCommand(trimmed))
7724
+ return;
7725
+ const expanded = await this.expandLocalInput(trimmed);
7726
+ if (expanded === null)
7727
+ return;
7728
+ await this.remote.sendPrompt(expanded, "steer");
7690
7729
  }
7691
7730
  async followUp(text2) {
7692
- await this.remote.sendPrompt(text2, "followUp");
7731
+ const trimmed = text2.trim();
7732
+ if (trimmed.startsWith("/") && await this._tryExecuteExtensionCommand(trimmed))
7733
+ return;
7734
+ const expanded = await this.expandLocalInput(trimmed);
7735
+ if (expanded === null)
7736
+ return;
7737
+ await this.remote.sendPrompt(expanded, "followUp");
7693
7738
  }
7694
7739
  async abort() {
7695
7740
  await this.remote.abort();
@@ -7802,6 +7847,9 @@ function createRemoteBashOperations(controller, excludeFromContext) {
7802
7847
  };
7803
7848
  }
7804
7849
 
7850
+ // packages/cli/src/commands/_spinner.ts
7851
+ var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
7852
+
7805
7853
  // packages/cli/src/commands/_pi-worker-bridge-extension.ts
7806
7854
  function recordOf2(value) {
7807
7855
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
@@ -7819,6 +7867,50 @@ function asText(value) {
7819
7867
  return String(value);
7820
7868
  }
7821
7869
  }
7870
+ function names(value, key = "name") {
7871
+ if (!Array.isArray(value))
7872
+ return [];
7873
+ return value.flatMap((entry) => {
7874
+ if (typeof entry === "string")
7875
+ return [entry];
7876
+ const record = recordOf2(entry);
7877
+ const name = record?.[key];
7878
+ return typeof name === "string" ? [name] : [];
7879
+ });
7880
+ }
7881
+ function renderWorkerCapabilities(capabilities) {
7882
+ const lines = ["Worker session capabilities (in effect for this run)"];
7883
+ const tools = Array.isArray(capabilities.tools) ? capabilities.tools : [];
7884
+ const activeTools = tools.flatMap((tool) => {
7885
+ const record = recordOf2(tool);
7886
+ return record && record.active === true && typeof record.name === "string" ? [record.name] : [];
7887
+ });
7888
+ const inactiveCount = tools.length - activeTools.length;
7889
+ lines.push(` tools ${activeTools.join(", ") || "(none)"}${inactiveCount > 0 ? ` (+${inactiveCount} inactive)` : ""}`);
7890
+ const extensions = Array.isArray(capabilities.extensions) ? capabilities.extensions : [];
7891
+ const extensionLabels = extensions.flatMap((entry) => {
7892
+ const record = recordOf2(entry);
7893
+ if (!record)
7894
+ return [];
7895
+ const path = typeof record.path === "string" ? record.path : "";
7896
+ const short = path.split("/").filter(Boolean).slice(-2).join("/") || path || "extension";
7897
+ return [short];
7898
+ });
7899
+ lines.push(` extensions ${extensionLabels.join(", ") || "(none)"}`);
7900
+ const hookEvents = names(capabilities.hookEvents);
7901
+ const hookList = Array.isArray(capabilities.hookEvents) ? capabilities.hookEvents.map(asText).filter(Boolean) : hookEvents;
7902
+ lines.push(` hooks ${hookList.join(", ") || "(none)"}`);
7903
+ lines.push(` skills ${names(capabilities.skills).join(", ") || "(none)"}`);
7904
+ lines.push(` prompts ${names(capabilities.prompts).join(", ") || "(none)"}`);
7905
+ const model = typeof capabilities.model === "string" ? capabilities.model : "(unknown)";
7906
+ const thinking = typeof capabilities.thinkingLevel === "string" ? capabilities.thinkingLevel : "";
7907
+ const cwd = typeof capabilities.cwd === "string" ? capabilities.cwd : "";
7908
+ lines.push(` model ${model}${thinking ? ` \xB7 ${thinking}` : ""}`);
7909
+ if (cwd)
7910
+ lines.push(` cwd ${cwd}`);
7911
+ lines.push(" (worker commands are in your palette as [worker \u2026] \xB7 /worker shows this again)");
7912
+ return lines;
7913
+ }
7822
7914
  async function answerExtensionUiRequest(options, ctx, request) {
7823
7915
  const requestId = String(request.requestId ?? request.id ?? `ui-${Date.now()}`);
7824
7916
  const method = String(request.method ?? request.type ?? "input");
@@ -7845,7 +7937,7 @@ async function answerExtensionUiRequest(options, ctx, request) {
7845
7937
  ctx.ui.notify(`Failed to answer worker UI request: ${error instanceof Error ? error.message : String(error)}`, "error");
7846
7938
  }
7847
7939
  }
7848
- var LOCALLY_OWNED_COMMANDS = new Set(["detach", "quit", "q", "stop", "settings", "model", "thinking", "compact", "session", "name", "reload"]);
7940
+ var LOCALLY_OWNED_COMMANDS = new Set(["detach", "quit", "q", "stop", "worker", "settings", "model", "thinking", "compact", "session", "name", "reload"]);
7849
7941
  function registerDaemonCommands(pi, options, ctx, commands, registered) {
7850
7942
  for (const command of commands) {
7851
7943
  const record = recordOf2(command);
@@ -7873,6 +7965,21 @@ function registerDaemonCommands(pi, options, ctx, commands, registered) {
7873
7965
  function createRigWorkerPiBridgeExtension(options) {
7874
7966
  return (pi) => {
7875
7967
  const registeredDaemonCommands = new Set;
7968
+ let capabilityLines = null;
7969
+ let statusText = "connecting to worker session";
7970
+ let busy = true;
7971
+ let connected = false;
7972
+ let frame = 0;
7973
+ let spinnerTimer = null;
7974
+ const renderStatus = (ctx) => {
7975
+ const prefix = busy ? `${SPINNER_FRAMES[frame]} ` : connected ? "\u25CF " : "\u25CB ";
7976
+ ctx.ui.setStatus("rig-worker-pi", `${prefix}${statusText}`);
7977
+ };
7978
+ const setStatus = (ctx, text2, isBusy) => {
7979
+ statusText = text2;
7980
+ busy = isBusy;
7981
+ renderStatus(ctx);
7982
+ };
7876
7983
  pi.registerCommand("detach", {
7877
7984
  description: "Detach from this run; the worker keeps going",
7878
7985
  handler: async (_args, ctx) => {
@@ -7888,31 +7995,57 @@ function createRigWorkerPiBridgeExtension(options) {
7888
7995
  ctx.shutdown();
7889
7996
  }
7890
7997
  });
7998
+ pi.registerCommand("worker", {
7999
+ description: "Show the worker session's real capabilities (tools, extensions, hooks, skills)",
8000
+ handler: async (_args, ctx) => {
8001
+ if (capabilityLines)
8002
+ ctx.ui.setWidget("rig-worker-capabilities", capabilityLines, { placement: "aboveEditor" });
8003
+ else
8004
+ ctx.ui.notify("Worker capabilities are not available yet (still connecting).", "info");
8005
+ }
8006
+ });
7891
8007
  pi.on("user_bash", (event) => ({
7892
8008
  operations: createRemoteBashOperations(options.controller, event.excludeFromContext === true)
7893
8009
  }));
7894
8010
  pi.on("session_start", async (_event, ctx) => {
7895
- ctx.ui.setTitle("Rig \xB7 worker session");
7896
- ctx.ui.setStatus("rig-worker-pi", "connecting to worker session");
7897
- ctx.ui.notify(`Attached to Rig run ${options.runId}. Native Pi, remote brain \u2014 /detach exits, /stop cancels the run.`, "info");
8011
+ ctx.ui.setTitle("Rig \xB7 enriched bundled Pi");
8012
+ setStatus(ctx, "waiting for worker Pi daemon", true);
8013
+ spinnerTimer = setInterval(() => {
8014
+ frame = (frame + 1) % SPINNER_FRAMES.length;
8015
+ if (busy)
8016
+ renderStatus(ctx);
8017
+ }, 150);
8018
+ ctx.ui.notify(`Enriched bundled Pi \u2014 native UI + Rig layers, worker brain. Attached to run ${options.runId}. /worker shows live capabilities \xB7 /detach exits \xB7 /stop cancels.`, "info");
7898
8019
  if (options.initialMessageSent)
7899
8020
  ctx.ui.notify("Initial message sent to the worker Pi daemon.", "info");
7900
8021
  const nativeUi = ctx.ui;
7901
8022
  options.controller.setUiHooks({
7902
- onStatusText: (text2) => ctx.ui.setStatus("rig-worker-pi", text2),
7903
- onActivity: (label, detail) => ctx.ui.setStatus("rig-worker-pi", [label, detail].filter(Boolean).join(" \u2014 ")),
7904
- onConnectionChange: (connected) => ctx.ui.setStatus("rig-worker-pi", connected ? "worker session live" : "worker session disconnected"),
8023
+ onStatusText: (text2) => setStatus(ctx, text2, !connected),
8024
+ onActivity: (label, detail) => {
8025
+ const active = label !== "idle" && !/complete|ready/i.test(label);
8026
+ setStatus(ctx, [label, detail].filter(Boolean).join(" \u2014 "), active);
8027
+ if (/agent running|tool:/.test(label))
8028
+ ctx.ui.setWidget("rig-worker-capabilities", undefined);
8029
+ },
8030
+ onConnectionChange: (nextConnected) => {
8031
+ connected = nextConnected;
8032
+ setStatus(ctx, nextConnected ? "worker session live" : "worker session disconnected", false);
8033
+ },
7905
8034
  onError: (message2) => ctx.ui.notify(message2, "error"),
7906
8035
  onExtensionUiRequest: (request) => {
7907
8036
  answerExtensionUiRequest(options, ctx, request);
7908
8037
  },
7909
- onCatchUp: (messages, commands) => {
8038
+ onCatchUp: (messages, commands, capabilities) => {
7910
8039
  if (nativeUi.appendSessionMessages)
7911
8040
  nativeUi.appendSessionMessages(messages);
7912
8041
  const cwd = options.controller.status.cwd;
7913
8042
  if (nativeUi.setDisplayCwd && cwd)
7914
8043
  nativeUi.setDisplayCwd(cwd);
7915
8044
  registerDaemonCommands(pi, options, ctx, commands, registeredDaemonCommands);
8045
+ if (capabilities) {
8046
+ capabilityLines = renderWorkerCapabilities(capabilities);
8047
+ ctx.ui.setWidget("rig-worker-capabilities", capabilityLines, { placement: "aboveEditor" });
8048
+ }
7916
8049
  }
7917
8050
  });
7918
8051
  options.controller.connect().catch((error) => {
@@ -7920,6 +8053,8 @@ function createRigWorkerPiBridgeExtension(options) {
7920
8053
  });
7921
8054
  });
7922
8055
  pi.on("session_shutdown", () => {
8056
+ if (spinnerTimer)
8057
+ clearInterval(spinnerTimer);
7923
8058
  options.controller.close();
7924
8059
  });
7925
8060
  };
@@ -7961,6 +8096,9 @@ async function attachRunBundledPiFrontend(context, input) {
7961
8096
  initialMessageSent: input.steered === true
7962
8097
  })
7963
8098
  ],
8099
+ noExtensions: true,
8100
+ noSkills: true,
8101
+ noPromptTemplates: true,
7964
8102
  noContextFiles: true
7965
8103
  }
7966
8104
  });
@@ -7995,7 +8133,7 @@ async function attachRunBundledPiFrontend(context, input) {
7995
8133
  timelineCursor: null,
7996
8134
  steered: input.steered === true,
7997
8135
  detached,
7998
- rendered: "native bundled Pi frontend with remote worker session runtime"
8136
+ rendered: "enriched bundled Pi frontend with remote worker session runtime"
7999
8137
  };
8000
8138
  }
8001
8139
 
@@ -8792,7 +8930,7 @@ var PRIMARY_GROUPS = [
8792
8930
  { command: "list", description: "List recent runs from the selected server or local state.", primary: true },
8793
8931
  { command: "status", description: "Render active and recent run groups.", primary: true },
8794
8932
  { command: "show <id>|--run <id> [--raw]", description: "Show a human run summary; --raw prints the full payload.", primary: true },
8795
- { command: "attach <run-id>|--run <id> [--follow]", description: "Attach to the run; --follow launches native bundled Pi for live Pi runs.", primary: true },
8933
+ { command: "attach <run-id>|--run <id> [--follow]", description: "Attach to the run; --follow opens the enriched bundled Pi (worker brain).", primary: true },
8796
8934
  { command: "stop [<run-id>|--run <id>]", description: "Request stop for one run or local active runs.", primary: true },
8797
8935
  { command: "steer <run-id> --message <text>", description: "Queue a steering message into a live worker without attaching." },
8798
8936
  { command: "timeline --run <id> [--follow]", description: "Stream raw run timeline events." },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@h-rig/cli",
3
- "version": "0.0.6-alpha.41",
3
+ "version": "0.0.6-alpha.43",
4
4
  "type": "module",
5
5
  "description": "Rig package",
6
6
  "license": "UNLICENSED",
@@ -23,11 +23,11 @@
23
23
  },
24
24
  "dependencies": {
25
25
  "@clack/prompts": "^1.2.0",
26
- "@earendil-works/pi-coding-agent": "npm:@h-rig/pi-coding-agent@0.0.6-alpha.41",
27
- "@rig/core": "npm:@h-rig/core@0.0.6-alpha.41",
28
- "@rig/runtime": "npm:@h-rig/runtime@0.0.6-alpha.41",
29
- "@rig/client": "npm:@h-rig/client@0.0.6-alpha.41",
30
- "@rig/server": "npm:@h-rig/server@0.0.6-alpha.41",
26
+ "@earendil-works/pi-coding-agent": "npm:@h-rig/pi-coding-agent@0.0.6-alpha.43",
27
+ "@rig/core": "npm:@h-rig/core@0.0.6-alpha.43",
28
+ "@rig/runtime": "npm:@h-rig/runtime@0.0.6-alpha.43",
29
+ "@rig/client": "npm:@h-rig/client@0.0.6-alpha.43",
30
+ "@rig/server": "npm:@h-rig/server@0.0.6-alpha.43",
31
31
  "picocolors": "^1.1.1"
32
32
  }
33
33
  }