@h-rig/cli 0.0.6-alpha.42 → 0.0.6-alpha.44

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,21 +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
7722
  const trimmed = text2.trim();
7690
7723
  if (trimmed.startsWith("/") && await this._tryExecuteExtensionCommand(trimmed))
7691
7724
  return;
7692
- await this.remote.sendPrompt(trimmed, "steer");
7725
+ const expanded = await this.expandLocalInput(trimmed);
7726
+ if (expanded === null)
7727
+ return;
7728
+ await this.remote.sendPrompt(expanded, "steer");
7693
7729
  }
7694
7730
  async followUp(text2) {
7695
7731
  const trimmed = text2.trim();
7696
7732
  if (trimmed.startsWith("/") && await this._tryExecuteExtensionCommand(trimmed))
7697
7733
  return;
7698
- await this.remote.sendPrompt(trimmed, "followUp");
7734
+ const expanded = await this.expandLocalInput(trimmed);
7735
+ if (expanded === null)
7736
+ return;
7737
+ await this.remote.sendPrompt(expanded, "followUp");
7699
7738
  }
7700
7739
  async abort() {
7701
7740
  await this.remote.abort();
@@ -7808,6 +7847,9 @@ function createRemoteBashOperations(controller, excludeFromContext) {
7808
7847
  };
7809
7848
  }
7810
7849
 
7850
+ // packages/cli/src/commands/_spinner.ts
7851
+ var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
7852
+
7811
7853
  // packages/cli/src/commands/_pi-worker-bridge-extension.ts
7812
7854
  function recordOf2(value) {
7813
7855
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
@@ -7825,6 +7867,50 @@ function asText(value) {
7825
7867
  return String(value);
7826
7868
  }
7827
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
+ }
7828
7914
  async function answerExtensionUiRequest(options, ctx, request) {
7829
7915
  const requestId = String(request.requestId ?? request.id ?? `ui-${Date.now()}`);
7830
7916
  const method = String(request.method ?? request.type ?? "input");
@@ -7851,7 +7937,7 @@ async function answerExtensionUiRequest(options, ctx, request) {
7851
7937
  ctx.ui.notify(`Failed to answer worker UI request: ${error instanceof Error ? error.message : String(error)}`, "error");
7852
7938
  }
7853
7939
  }
7854
- 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"]);
7855
7941
  function registerDaemonCommands(pi, options, ctx, commands, registered) {
7856
7942
  for (const command of commands) {
7857
7943
  const record = recordOf2(command);
@@ -7879,6 +7965,21 @@ function registerDaemonCommands(pi, options, ctx, commands, registered) {
7879
7965
  function createRigWorkerPiBridgeExtension(options) {
7880
7966
  return (pi) => {
7881
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
+ };
7882
7983
  pi.registerCommand("detach", {
7883
7984
  description: "Detach from this run; the worker keeps going",
7884
7985
  handler: async (_args, ctx) => {
@@ -7894,31 +7995,57 @@ function createRigWorkerPiBridgeExtension(options) {
7894
7995
  ctx.shutdown();
7895
7996
  }
7896
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
+ });
7897
8007
  pi.on("user_bash", (event) => ({
7898
8008
  operations: createRemoteBashOperations(options.controller, event.excludeFromContext === true)
7899
8009
  }));
7900
8010
  pi.on("session_start", async (_event, ctx) => {
7901
- ctx.ui.setTitle("Rig \xB7 worker session");
7902
- ctx.ui.setStatus("rig-worker-pi", "connecting to worker session");
7903
- 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");
7904
8019
  if (options.initialMessageSent)
7905
8020
  ctx.ui.notify("Initial message sent to the worker Pi daemon.", "info");
7906
8021
  const nativeUi = ctx.ui;
7907
8022
  options.controller.setUiHooks({
7908
- onStatusText: (text2) => ctx.ui.setStatus("rig-worker-pi", text2),
7909
- onActivity: (label, detail) => ctx.ui.setStatus("rig-worker-pi", [label, detail].filter(Boolean).join(" \u2014 ")),
7910
- 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
+ },
7911
8034
  onError: (message2) => ctx.ui.notify(message2, "error"),
7912
8035
  onExtensionUiRequest: (request) => {
7913
8036
  answerExtensionUiRequest(options, ctx, request);
7914
8037
  },
7915
- onCatchUp: (messages, commands) => {
8038
+ onCatchUp: (messages, commands, capabilities) => {
7916
8039
  if (nativeUi.appendSessionMessages)
7917
8040
  nativeUi.appendSessionMessages(messages);
7918
8041
  const cwd = options.controller.status.cwd;
7919
8042
  if (nativeUi.setDisplayCwd && cwd)
7920
8043
  nativeUi.setDisplayCwd(cwd);
7921
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
+ }
7922
8049
  }
7923
8050
  });
7924
8051
  options.controller.connect().catch((error) => {
@@ -7926,6 +8053,8 @@ function createRigWorkerPiBridgeExtension(options) {
7926
8053
  });
7927
8054
  });
7928
8055
  pi.on("session_shutdown", () => {
8056
+ if (spinnerTimer)
8057
+ clearInterval(spinnerTimer);
7929
8058
  options.controller.close();
7930
8059
  });
7931
8060
  };
@@ -7951,7 +8080,8 @@ async function attachRunBundledPiFrontend(context, input) {
7951
8080
  const tempSessionDir = mkdtempSync(join2(tmpdir(), "rig-pi-frontend-sessions-"));
7952
8081
  const restoreEnv = setTemporaryEnv({
7953
8082
  PI_CODING_AGENT_SESSION_DIR: tempSessionDir,
7954
- PI_SKIP_VERSION_CHECK: "1"
8083
+ PI_SKIP_VERSION_CHECK: "1",
8084
+ PI_HIDDEN_COMMANDS: "import,fork,clone,tree,new,resume,trust"
7955
8085
  });
7956
8086
  const controller = new RigRemoteSessionController({ context, runId: input.runId });
7957
8087
  const createRemoteRuntime = async ({ cwd, agentDir, sessionManager, sessionStartEvent }) => {
@@ -7967,6 +8097,9 @@ async function attachRunBundledPiFrontend(context, input) {
7967
8097
  initialMessageSent: input.steered === true
7968
8098
  })
7969
8099
  ],
8100
+ noExtensions: true,
8101
+ noSkills: true,
8102
+ noPromptTemplates: true,
7970
8103
  noContextFiles: true
7971
8104
  }
7972
8105
  });
@@ -8001,7 +8134,7 @@ async function attachRunBundledPiFrontend(context, input) {
8001
8134
  timelineCursor: null,
8002
8135
  steered: input.steered === true,
8003
8136
  detached,
8004
- rendered: "native bundled Pi frontend with remote worker session runtime"
8137
+ rendered: "enriched bundled Pi frontend with remote worker session runtime"
8005
8138
  };
8006
8139
  }
8007
8140
 
@@ -8798,7 +8931,7 @@ var PRIMARY_GROUPS = [
8798
8931
  { command: "list", description: "List recent runs from the selected server or local state.", primary: true },
8799
8932
  { command: "status", description: "Render active and recent run groups.", primary: true },
8800
8933
  { command: "show <id>|--run <id> [--raw]", description: "Show a human run summary; --raw prints the full payload.", primary: true },
8801
- { command: "attach <run-id>|--run <id> [--follow]", description: "Attach to the run; --follow launches native bundled Pi for live Pi runs.", primary: true },
8934
+ { command: "attach <run-id>|--run <id> [--follow]", description: "Attach to the run; --follow opens the enriched bundled Pi (worker brain).", primary: true },
8802
8935
  { command: "stop [<run-id>|--run <id>]", description: "Request stop for one run or local active runs.", primary: true },
8803
8936
  { command: "steer <run-id> --message <text>", description: "Queue a steering message into a live worker without attaching." },
8804
8937
  { 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.42",
3
+ "version": "0.0.6-alpha.44",
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.42",
27
- "@rig/core": "npm:@h-rig/core@0.0.6-alpha.42",
28
- "@rig/runtime": "npm:@h-rig/runtime@0.0.6-alpha.42",
29
- "@rig/client": "npm:@h-rig/client@0.0.6-alpha.42",
30
- "@rig/server": "npm:@h-rig/server@0.0.6-alpha.42",
26
+ "@earendil-works/pi-coding-agent": "npm:@h-rig/pi-coding-agent@0.0.6-alpha.44",
27
+ "@rig/core": "npm:@h-rig/core@0.0.6-alpha.44",
28
+ "@rig/runtime": "npm:@h-rig/runtime@0.0.6-alpha.44",
29
+ "@rig/client": "npm:@h-rig/client@0.0.6-alpha.44",
30
+ "@rig/server": "npm:@h-rig/server@0.0.6-alpha.44",
31
31
  "picocolors": "^1.1.1"
32
32
  }
33
33
  }