@pipod/cli 0.1.20 → 0.1.21

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;
@@ -14996,6 +15032,12 @@ function renderPodLines(pods) {
14996
15032
  async function selectAccountPod(client, podRef, action, cwd) {
14997
15033
  if (podRef) {
14998
15034
  if (isFullUuid(podRef)) return client.getPod(podRef.toLowerCase());
15035
+ const found = await client.lookupPodRef(podRef);
15036
+ if (found !== null) {
15037
+ if (found.total > 1) throw ambiguousPodRef(podRef, found.matches, found.total);
15038
+ if (found.pod) return found.pod;
15039
+ throw new PiPodError(`no pod matches "${podRef}"`, { hint: "see `pipod list --all`" });
15040
+ }
14999
15041
  const pods2 = (await listAllPods(client, {})).pods;
15000
15042
  const named = pods2.filter((pod) => pod.name === podRef);
15001
15043
  if (named.length === 1) return named[0];
@@ -15022,10 +15064,11 @@ ${podChoiceLines(pods)}`
15022
15064
  }
15023
15065
  return pods[0];
15024
15066
  }
15025
- function ambiguousPodRef(ref, pods) {
15026
- return new PiPodError(`"${ref}" matches ${pods.length} pods`, {
15067
+ function ambiguousPodRef(ref, pods, total = pods.length) {
15068
+ return new PiPodError(`"${ref}" matches ${total} pods`, {
15027
15069
  hint: `use a longer ref:
15028
- ${podChoiceLines(pods)}`
15070
+ ${podChoiceLines(pods)}` + (total > pods.length ? `
15071
+ \u2026 showing the first ${pods.length} matches` : "")
15029
15072
  });
15030
15073
  }
15031
15074
  function podChoiceLines(pods) {