@pipod/cli 0.1.20 → 0.1.22

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
@@ -1873,6 +1873,10 @@ var AccountClient = class {
1873
1873
  listPods(query = {}) {
1874
1874
  return this.request("/pods", { query });
1875
1875
  }
1876
+ /** Null means an older server lacks lookup, not that the ref had no matches. */
1877
+ lookupPodRef(ref) {
1878
+ return this.request(`/pods/by-ref/${encodeURIComponent(ref)}`, { allow404: true });
1879
+ }
1876
1880
  /** `waitMs` long-polls: a supporting server answers on the next pod change; older servers ignore it. */
1877
1881
  getPod(id, opts = {}) {
1878
1882
  const waitMs = opts.waitMs != null && opts.waitMs > 0 ? Math.floor(opts.waitMs) : void 0;
@@ -5068,19 +5072,24 @@ function displayRef(id, kind) {
5068
5072
  const tail = id.replaceAll("-", "").slice(-DISPLAY_TAIL_LENGTH).toLowerCase();
5069
5073
  return `${kind === "pod" ? "p" : "j"}-${tail}`;
5070
5074
  }
5071
- function matchesRef(id, ref) {
5072
- const normalizedId = id.toLowerCase();
5073
- const normalizedRef = ref.toLowerCase();
5074
- if (FULL_UUID.test(normalizedRef)) return normalizedId === normalizedRef;
5075
- const prefixed = /^[pj]-(.*)$/i.exec(normalizedRef);
5075
+ function parseRef(ref) {
5076
+ const normalized = ref.toLowerCase();
5077
+ if (FULL_UUID.test(normalized)) return { kind: "uuid", value: normalized };
5078
+ const prefixed = /^[pj]-(.*)$/i.exec(normalized);
5076
5079
  if (prefixed) {
5077
- const tail = prefixed[1];
5078
- assertUsableHexRef(ref, tail);
5079
- return normalizedId.replaceAll("-", "").endsWith(tail);
5080
+ assertUsableHexRef(ref, prefixed[1]);
5081
+ return { kind: "tail", value: prefixed[1] };
5080
5082
  }
5081
- if (!HEX.test(normalizedRef)) return false;
5082
- assertUsableHexRef(ref, normalizedRef);
5083
- return normalizedId.startsWith(normalizedRef) || normalizedId.replaceAll("-", "").endsWith(normalizedRef);
5083
+ if (!HEX.test(normalized)) return null;
5084
+ assertUsableHexRef(ref, normalized);
5085
+ return { kind: "hex", value: normalized };
5086
+ }
5087
+ function matchesRef(id, ref) {
5088
+ const pattern = parseRef(ref);
5089
+ if (!pattern) return false;
5090
+ const normalizedId = id.toLowerCase();
5091
+ if (pattern.kind === "uuid") return normalizedId === pattern.value;
5092
+ return normalizedId.replaceAll("-", "").endsWith(pattern.value) || pattern.kind === "hex" && normalizedId.startsWith(pattern.value);
5084
5093
  }
5085
5094
  function assertUsableHexRef(ref, hex) {
5086
5095
  if (!HEX.test(hex)) {
@@ -6577,6 +6586,7 @@ var RemoteStateCache = class {
6577
6586
  sessionRefreshRequested = false;
6578
6587
  expectedRefreshLeaf = NO_EXPECTED_LEAF;
6579
6588
  cacheGeneration = 0;
6589
+ modelsRefresh = null;
6580
6590
  replacementInProgress = false;
6581
6591
  labelStates = /* @__PURE__ */ new Map();
6582
6592
  seedBridge = null;
@@ -6812,11 +6822,22 @@ var RemoteStateCache = class {
6812
6822
  }
6813
6823
  throw lastError ?? new Error("pod session refresh could not be reconciled");
6814
6824
  }
6815
- async refreshModels() {
6816
- try {
6817
- this.availableModels = await this.rpc.getAvailableModels();
6818
- } catch {
6819
- }
6825
+ refreshModels() {
6826
+ const generation = this.cacheGeneration;
6827
+ if (this.modelsRefresh?.generation === generation) return this.modelsRefresh.promise;
6828
+ const promise = (async () => {
6829
+ try {
6830
+ const models = await this.rpc.getAvailableModels();
6831
+ if (generation === this.cacheGeneration) this.availableModels = models;
6832
+ } catch {
6833
+ }
6834
+ })();
6835
+ const entry = { generation, promise };
6836
+ this.modelsRefresh = entry;
6837
+ void promise.then(() => {
6838
+ if (this.modelsRefresh === entry) this.modelsRefresh = null;
6839
+ });
6840
+ return promise;
6820
6841
  }
6821
6842
  async refreshCommands() {
6822
6843
  try {
@@ -11434,8 +11455,7 @@ function createRemoteRuntime(opts) {
11434
11455
  treeBridge,
11435
11456
  init: async () => {
11436
11457
  await cache.init();
11437
- await refreshThinkingLevels();
11438
- await authBridge.refresh();
11458
+ await Promise.all([refreshThinkingLevels(), authBridge.refresh(), cache.refreshModels()]);
11439
11459
  await seedScopedModels();
11440
11460
  if (opts.attestedExtensionPaths?.length) {
11441
11461
  try {
@@ -12403,6 +12423,7 @@ var GatewayRpcClient = class _GatewayRpcClient extends RpcClientBase {
12403
12423
  /** False between adopting a skewed hello and readiness replacing it; ordinary RPC is gated. */
12404
12424
  piVersionReady = false;
12405
12425
  idPrefix = `cli-${randomBytes5(4).toString("hex")}-`;
12426
+ availableModelsRequest = null;
12406
12427
  modelsRequest = null;
12407
12428
  pendingSemantic = /* @__PURE__ */ new Map();
12408
12429
  /** Auxiliary completions multiplex by caller id — unlike single-slot semantic queries. */
@@ -12556,6 +12577,20 @@ var GatewayRpcClient = class _GatewayRpcClient extends RpcClientBase {
12556
12577
  }
12557
12578
  return promise;
12558
12579
  }
12580
+ /** Model and thinking consumers share one semantic catalog, not two large replies. */
12581
+ getAvailableModels() {
12582
+ if (this.availableModelsRequest) return this.availableModelsRequest;
12583
+ const task = this.getModels().then((snapshot) => snapshot.models).catch((error2) => {
12584
+ if (error2 instanceof Error && error2.message === "timed out waiting for the gateway model catalog" && !this.userClosed && this.piVersionReady) return super.getAvailableModels();
12585
+ throw error2;
12586
+ });
12587
+ this.availableModelsRequest = task;
12588
+ const clear = () => {
12589
+ if (this.availableModelsRequest === task) this.availableModelsRequest = null;
12590
+ };
12591
+ void task.then(clear, clear);
12592
+ return task;
12593
+ }
12559
12594
  /** List pod-side sessions. A timeout or unsupported marker is an absent capability. */
12560
12595
  getSessions() {
12561
12596
  const absent = { sessions: [], workdir: "", complete: false, unsupported: true };
@@ -12913,6 +12948,7 @@ var GatewayRpcClient = class _GatewayRpcClient extends RpcClientBase {
12913
12948
  }
12914
12949
  }
12915
12950
  resetHandshakeState(podId) {
12951
+ this.availableModelsRequest = null;
12916
12952
  this.currentPodId = podId;
12917
12953
  this.hello = null;
12918
12954
  this.piExitCode = void 0;
@@ -14625,6 +14661,8 @@ ${choices.join("\n")}`,
14625
14661
  };
14626
14662
  let unwireDisconnectedQuit = () => {
14627
14663
  };
14664
+ let unwireKeyEncoding = () => {
14665
+ };
14628
14666
  let unwireKeyRepeat = () => {
14629
14667
  };
14630
14668
  let mode;
@@ -14632,6 +14670,7 @@ ${choices.join("\n")}`,
14632
14670
  await runtime.init();
14633
14671
  const { InteractiveMode } = await import("@earendil-works/pi-coding-agent");
14634
14672
  const { wirePodChords } = await import("./chords-SOJBLC6R.js");
14673
+ const { wireKeyEncodingGuard } = await import("./key-encoding-guard-6UOKKTJQ.js");
14635
14674
  const { wireKeyRepeatGuard } = await import("./key-repeat-guard-7OVKW5KD.js");
14636
14675
  const { guardStdinFragments } = await import("./stdin-fragment-guard-SPIJC7GT.js");
14637
14676
  guardStdinFragments();
@@ -14639,12 +14678,14 @@ ${choices.join("\n")}`,
14639
14678
  runtime.bridge.setOnUiBound(() => {
14640
14679
  unwireChords();
14641
14680
  unwireDisconnectedQuit();
14681
+ unwireKeyEncoding();
14642
14682
  unwireKeyRepeat();
14643
14683
  unwireChords = wirePodChords(runtime.bridge, runtime.router, chords);
14644
14684
  unwireDisconnectedQuit = wireDisconnectedQuit(
14645
14685
  runtime.bridge,
14646
14686
  () => connectionAllowsQuit(latestConnectionState)
14647
14687
  );
14688
+ unwireKeyEncoding = wireKeyEncodingGuard(runtime.bridge.ui);
14648
14689
  unwireKeyRepeat = wireKeyRepeatGuard(runtime.bridge.ui);
14649
14690
  });
14650
14691
  const tuiMode = opts.tuiMode ?? tuiModeFromArgv(context.config.pi.args);
@@ -14675,6 +14716,7 @@ ${choices.join("\n")}`,
14675
14716
  runtime.bridge.setOnUiBound(null);
14676
14717
  unwireChords();
14677
14718
  unwireDisconnectedQuit();
14719
+ unwireKeyEncoding();
14678
14720
  unwireKeyRepeat();
14679
14721
  rpc.close();
14680
14722
  derived?.dispose();
@@ -14702,6 +14744,7 @@ ${choices.join("\n")}`,
14702
14744
  runtime.bridge.setOnUiBound(null);
14703
14745
  unwireChords();
14704
14746
  unwireDisconnectedQuit();
14747
+ unwireKeyEncoding();
14705
14748
  unwireKeyRepeat();
14706
14749
  process.off("SIGHUP", onHangUp);
14707
14750
  process.off("SIGTERM", onHangUp);
@@ -14996,6 +15039,12 @@ function renderPodLines(pods) {
14996
15039
  async function selectAccountPod(client, podRef, action, cwd) {
14997
15040
  if (podRef) {
14998
15041
  if (isFullUuid(podRef)) return client.getPod(podRef.toLowerCase());
15042
+ const found = await client.lookupPodRef(podRef);
15043
+ if (found !== null) {
15044
+ if (found.total > 1) throw ambiguousPodRef(podRef, found.matches, found.total);
15045
+ if (found.pod) return found.pod;
15046
+ throw new PiPodError(`no pod matches "${podRef}"`, { hint: "see `pipod list --all`" });
15047
+ }
14999
15048
  const pods2 = (await listAllPods(client, {})).pods;
15000
15049
  const named = pods2.filter((pod) => pod.name === podRef);
15001
15050
  if (named.length === 1) return named[0];
@@ -15022,10 +15071,11 @@ ${podChoiceLines(pods)}`
15022
15071
  }
15023
15072
  return pods[0];
15024
15073
  }
15025
- function ambiguousPodRef(ref, pods) {
15026
- return new PiPodError(`"${ref}" matches ${pods.length} pods`, {
15074
+ function ambiguousPodRef(ref, pods, total = pods.length) {
15075
+ return new PiPodError(`"${ref}" matches ${total} pods`, {
15027
15076
  hint: `use a longer ref:
15028
- ${podChoiceLines(pods)}`
15077
+ ${podChoiceLines(pods)}` + (total > pods.length ? `
15078
+ \u2026 showing the first ${pods.length} matches` : "")
15029
15079
  });
15030
15080
  }
15031
15081
  function podChoiceLines(pods) {