@pipod/cli 0.1.7 → 0.1.9

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/cli.js CHANGED
@@ -583,7 +583,7 @@ import * as path5 from "path";
583
583
  import * as fs from "fs";
584
584
  import * as path from "path";
585
585
  var HOST_PI_AGENT_SUBPATH = path.join(".pi", "agent");
586
- var HOST_COUPLED_SETTINGS_KEYS = ["hooks", "mcpServers"];
586
+ var HOST_COUPLED_SETTINGS_KEYS = ["hooks", "mcpServers", "deviceId", "trackingId"];
587
587
  var DEFAULT_HOST_CONFIG = {
588
588
  settings: true,
589
589
  packages: true
@@ -6520,7 +6520,6 @@ import * as path17 from "path";
6520
6520
  import { promisify as promisify2 } from "util";
6521
6521
 
6522
6522
  // src/client/runtime/local-extensions.ts
6523
- import { randomUUID } from "crypto";
6524
6523
  import * as fs17 from "fs";
6525
6524
  import * as path16 from "path";
6526
6525
 
@@ -7208,7 +7207,7 @@ function branchOf(entries, fromId) {
7208
7207
  }
7209
7208
  async function createLocalExtensionHost(opts) {
7210
7209
  if (opts.paths.length === 0) return null;
7211
- const { cache, bridge, rpc } = opts;
7210
+ const { cache, bridge } = opts;
7212
7211
  const notifyWhenBound = (message, type) => {
7213
7212
  bridge.onUiBound(() => bridge.notify(message, type));
7214
7213
  };
@@ -7271,48 +7270,6 @@ async function createLocalExtensionHost(opts) {
7271
7270
  resetLeaf: throwMutator("resetLeaf")
7272
7271
  };
7273
7272
  const runner = new ExtensionRunnerClass(kept, runtime, opts.hostCwd, sessionManagerFacade, opts.modelRegistry);
7274
- let appendEntryWarned = false;
7275
- const appendEntryUnavailable = (reason) => {
7276
- if (appendEntryWarned) return;
7277
- appendEntryWarned = true;
7278
- notifyWhenBound(`pod extension appendEntry: ${reason} \u2014 the entry was not recorded`, "warning");
7279
- };
7280
- const supportsAppendEntry = () => cache.commands.some((command) => {
7281
- const candidate = command;
7282
- return candidate.name === APPEND_ENTRY_COMMAND && candidate.source === "extension";
7283
- });
7284
- const sendAppendEntry = (customType, data) => {
7285
- if (typeof customType !== "string" || customType.length === 0 || customType.length > APPEND_ENTRY_MAX_CUSTOM_TYPE_LENGTH) {
7286
- appendEntryUnavailable(`invalid custom type ${JSON.stringify(customType).slice(0, 64)}`);
7287
- return;
7288
- }
7289
- if (!supportsAppendEntry()) {
7290
- appendEntryUnavailable("this pod runs an older pi pod extension (restart Pi in the pod to update it)");
7291
- return;
7292
- }
7293
- const request = {
7294
- v: APPEND_ENTRY_PROTOCOL_VERSION,
7295
- id: randomUUID(),
7296
- op: "append-entry",
7297
- customType,
7298
- ...data !== void 0 ? { data } : {}
7299
- };
7300
- let encoded;
7301
- try {
7302
- encoded = Buffer.from(JSON.stringify(request), "utf8").toString("base64url");
7303
- } catch (error2) {
7304
- appendEntryUnavailable(`entry data is not serializable (${error2 instanceof Error ? error2.message : String(error2)})`);
7305
- return;
7306
- }
7307
- if (Buffer.byteLength(encoded, "utf8") > TREE_BRIDGE_MAX_ENCODED_REQUEST_BYTES) {
7308
- appendEntryUnavailable("entry data exceeds the bridge size limit");
7309
- return;
7310
- }
7311
- void rpc.prompt(`/${APPEND_ENTRY_COMMAND} ${encoded}`).then(() => cache.refreshTree().then(() => void 0)).catch((error2) => {
7312
- appendEntryUnavailable(error2 instanceof Error ? error2.message : String(error2));
7313
- debug(`append-entry bridge failed: ${error2 instanceof Error ? error2.message : String(error2)}`);
7314
- });
7315
- };
7316
7273
  const actions = {
7317
7274
  sendMessage: unavailable("pi.sendMessage", "conversation context is built in the pod"),
7318
7275
  sendUserMessage: (content, sendOptions) => {
@@ -7324,7 +7281,7 @@ async function createLocalExtensionHost(opts) {
7324
7281
  )
7325
7282
  );
7326
7283
  },
7327
- appendEntry: (customType, data) => sendAppendEntry(customType, data),
7284
+ appendEntry: opts.appendEntry,
7328
7285
  setSessionName: (name) => void opts.setSessionName(name),
7329
7286
  getSessionName: () => cache.state.sessionName,
7330
7287
  setLabel: (entryId, label2) => opts.setLabel(entryId, label2),
@@ -8514,6 +8471,54 @@ import {
8514
8471
  resolveModelScopeWithDiagnostics
8515
8472
  } from "@earendil-works/pi-coding-agent";
8516
8473
 
8474
+ // src/client/runtime/append-entry-bridge.ts
8475
+ import { randomUUID } from "crypto";
8476
+ function createAppendEntryBridge(opts) {
8477
+ const { rpc, cache, bridge } = opts;
8478
+ let warned = false;
8479
+ const unavailable3 = (reason) => {
8480
+ if (warned) return;
8481
+ warned = true;
8482
+ bridge.onUiBound(() => bridge.notify(`session entry not recorded: ${reason}`, "warning"));
8483
+ };
8484
+ const supported = () => cache.commands.some((command) => {
8485
+ const candidate = command;
8486
+ return candidate.name === APPEND_ENTRY_COMMAND && candidate.source === "extension";
8487
+ });
8488
+ return (customType, data) => {
8489
+ if (typeof customType !== "string" || customType.length === 0 || customType.length > APPEND_ENTRY_MAX_CUSTOM_TYPE_LENGTH) {
8490
+ unavailable3(`invalid custom type ${JSON.stringify(customType).slice(0, 64)}`);
8491
+ return;
8492
+ }
8493
+ if (!supported()) {
8494
+ unavailable3("this pod runs an older pi pod extension (restart Pi in the pod to update it)");
8495
+ return;
8496
+ }
8497
+ const request = {
8498
+ v: APPEND_ENTRY_PROTOCOL_VERSION,
8499
+ id: randomUUID(),
8500
+ op: "append-entry",
8501
+ customType,
8502
+ ...data !== void 0 ? { data } : {}
8503
+ };
8504
+ let encoded;
8505
+ try {
8506
+ encoded = Buffer.from(JSON.stringify(request), "utf8").toString("base64url");
8507
+ } catch (error2) {
8508
+ unavailable3(`entry data is not serializable (${error2 instanceof Error ? error2.message : String(error2)})`);
8509
+ return;
8510
+ }
8511
+ if (Buffer.byteLength(encoded, "utf8") > TREE_BRIDGE_MAX_ENCODED_REQUEST_BYTES) {
8512
+ unavailable3("entry data exceeds the bridge size limit");
8513
+ return;
8514
+ }
8515
+ void rpc.prompt(`/${APPEND_ENTRY_COMMAND} ${encoded}`).then(() => cache.refreshTree().then(() => void 0)).catch((error2) => {
8516
+ unavailable3(error2 instanceof Error ? error2.message : String(error2));
8517
+ debug(`append-entry bridge failed: ${error2 instanceof Error ? error2.message : String(error2)}`);
8518
+ });
8519
+ };
8520
+ }
8521
+
8517
8522
  // src/client/runtime/bridge.ts
8518
8523
  var HostBridge = class {
8519
8524
  /** Set exactly once, by the first ending path to fire; later writers lose. */
@@ -10588,6 +10593,7 @@ function createRemoteRuntime(opts) {
10588
10593
  const { rpc, cwd } = opts;
10589
10594
  const bridge = new HostBridge();
10590
10595
  const cache = new RemoteStateCache(rpc);
10596
+ const appendEntry = createAppendEntryBridge({ rpc, cache, bridge });
10591
10597
  const refreshThinkingLevels = async () => {
10592
10598
  cache.availableThinkingLevels = null;
10593
10599
  if (!opts.getAvailableThinkingLevels) return;
@@ -11017,6 +11023,8 @@ function createRemoteRuntime(opts) {
11017
11023
  // (including Mermaid) still compose — InteractiveMode appends these to its own chain.
11018
11024
  // Pod extension transforms remain honestly unavailable; client extensions supply theirs here.
11019
11025
  getMarkdownTransformers: () => localHost?.runner.getMarkdownTransformers() ?? [],
11026
+ // Tool renderers from client extensions wrap the built-in one, as in-process.
11027
+ resolveToolRenderers: (toolName, base) => localHost ? localHost.runner.resolveToolRenderers(toolName, base) : base(),
11020
11028
  getCommandDiagnostics: () => localHost?.runner.getCommandDiagnostics() ?? [],
11021
11029
  getShortcutDiagnostics: () => localHost?.runner.getShortcutDiagnostics() ?? [],
11022
11030
  getModelRegistry: () => localHost ? extensionModelRegistry : void 0,
@@ -11062,6 +11070,8 @@ function createRemoteRuntime(opts) {
11062
11070
  const sessionManager = {
11063
11071
  getCwd: () => cwd,
11064
11072
  getEntries: () => cache.entries,
11073
+ getBranch: () => cache.entries,
11074
+ getEntryCount: () => cache.entries.length,
11065
11075
  getLeafId: () => cache.leafId ?? void 0,
11066
11076
  getSessionDir: () => cwd,
11067
11077
  getSessionFile: () => cache.state.sessionFile,
@@ -11071,6 +11081,8 @@ function createRemoteRuntime(opts) {
11071
11081
  usesDefaultSessionDir: () => true,
11072
11082
  isPersisted: () => cache.state.sessionFile !== void 0,
11073
11083
  appendLabelChange: (entryId, label2) => trackLabelMutation(entryId, label2),
11084
+ /** pi's `/bug` records the report here; the entry belongs in the pod's session file. */
11085
+ appendCustomEntry: (customType, data) => appendEntry(customType, data),
11074
11086
  buildContextEntries: () => cache.entries
11075
11087
  };
11076
11088
  const session = {
@@ -11152,6 +11164,14 @@ function createRemoteRuntime(opts) {
11152
11164
  get hasPendingBashMessages() {
11153
11165
  return false;
11154
11166
  },
11167
+ // RPC reports neither the cache warmer nor where a virtual model routed a request, so the
11168
+ // footer and /settings show what pi shows when they are unavailable.
11169
+ get cacheWarmingStatus() {
11170
+ return void 0;
11171
+ },
11172
+ get routedModel() {
11173
+ return void 0;
11174
+ },
11155
11175
  // local-by-nature services
11156
11176
  settingsManager: remoteSettingsManager,
11157
11177
  sessionManager,
@@ -11203,6 +11223,8 @@ function createRemoteRuntime(opts) {
11203
11223
  abortBranchSummary: () => {
11204
11224
  },
11205
11225
  setAutoCompactionEnabled: (enabled) => mutate(() => rpc.setAutoCompaction(enabled)),
11226
+ /** Persisted like the /transport toggle; the warmer itself runs in the pod. */
11227
+ setCacheWarmingMode: (mode) => remoteSettingsManager.setCacheWarmingMode(mode),
11206
11228
  setAutoRetryEnabled: (enabled) => mutate(() => rpc.setAutoRetry(enabled)),
11207
11229
  abortRetry: () => rpc.abortRetry(),
11208
11230
  /** `!command` bash: streamed chunks arrive as bash_execution_update events with our id (§8). */
@@ -11423,7 +11445,7 @@ function createRemoteRuntime(opts) {
11423
11445
  hostCwd: cwd,
11424
11446
  cache,
11425
11447
  bridge,
11426
- rpc,
11448
+ appendEntry,
11427
11449
  getScopedModels: () => scopedModels,
11428
11450
  prompt,
11429
11451
  setModel: (model) => setRemoteModel(() => rpc.setModel(model.provider, model.id)),
@@ -17933,12 +17955,13 @@ async function removeCredential(args, flags) {
17933
17955
  });
17934
17956
  }
17935
17957
  const approved = await confirm(
17936
- `Remove the saved ${providerId} sign-in? Pods using it will need a reconnect.`,
17958
+ `Remove the saved ${providerId} sign-in? Pods stop using it.`,
17937
17959
  { nonInteractiveDefault: false, assumeYes: yes }
17938
17960
  );
17939
17961
  if (!approved) throw new CancelledError("Credential removal cancelled");
17940
17962
  await clientFor(flags).deleteModelCredential(providerId);
17941
- info(`removed the saved ${providerId} sign-in`);
17963
+ info(`removed the saved ${providerId} sign-in; pods stop using it`);
17964
+ info(`${providerId} still accepts it until you revoke it there; do that if a pod may have exposed it`);
17942
17965
  return 0;
17943
17966
  }
17944
17967
  function formatStatus(status) {