@candledottv/cli 0.11.40 → 0.11.41

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.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/dist/index.js +129 -25
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @candledottv/cli
2
2
 
3
- The Candle CLI (current version 0.11.39): authorize a device from your browser, keep your own keys
3
+ The Candle CLI (current version 0.11.41): authorize a device from your browser, keep your own keys
4
4
  in an encrypted vault on this machine, hand an agent a TEE wallet it can trade, and manage API
5
5
  keys, wallets, and setup health from the terminal. Zero runtime dependencies; the whole thing is
6
6
  one self-contained `dist/index.js` that runs under plain Node.
package/dist/index.js CHANGED
@@ -19050,14 +19050,59 @@ var init_protocol = __esm(() => {
19050
19050
  PASSKEY_ASSOCIATED_DOMAIN = `webcredentials:${PASSKEY_RP_ID}`;
19051
19051
  });
19052
19052
 
19053
+ // release-homes.json
19054
+ var release_homes_default;
19055
+ var init_release_homes = __esm(() => {
19056
+ release_homes_default = {
19057
+ note: "Where each CLI version is released from (spec docs/superpowers/specs/2026-10-23-candle-github-spec.md, section 9). Versions up to and including bridgeVersion are released, signed and verified in `legacy`; every later version in `current`. src/release.ts compiles this in, install.sh carries the same three values (a drift test holds them equal), release.yaml refuses a tag pushed in the wrong home, and sync-agentic.yaml never tags a version above bridgeVersion. Change it only together with a release plan.",
19058
+ bridgeVersion: "0.12.0",
19059
+ legacy: "candledottv/agentic",
19060
+ current: "candledottv/cli"
19061
+ };
19062
+ });
19063
+
19053
19064
  // src/release.ts
19054
19065
  function isPlainVersion(value) {
19055
19066
  return VERSION.test(value);
19056
19067
  }
19057
- function releaseIdentityUri(version) {
19068
+ function parseReleaseHomes(value) {
19069
+ const homes = value;
19070
+ const { bridgeVersion, legacy, current } = homes ?? {};
19071
+ if (typeof bridgeVersion !== "string" || !VERSION.test(bridgeVersion)) {
19072
+ throw new Error("release-homes.json: bridgeVersion must be three dot-separated numbers");
19073
+ }
19074
+ if (typeof legacy !== "string" || !REPOSITORY.test(legacy))
19075
+ throw new Error("release-homes.json: bad legacy");
19076
+ if (typeof current !== "string" || !REPOSITORY.test(current))
19077
+ throw new Error("release-homes.json: bad current");
19078
+ if (legacy === current)
19079
+ throw new Error("release-homes.json: legacy and current must differ");
19080
+ return { bridgeVersion, legacy, current };
19081
+ }
19082
+ function homeRepository(home) {
19083
+ return home === "legacy" ? LEGACY_RELEASE_REPOSITORY : CURRENT_RELEASE_REPOSITORY;
19084
+ }
19085
+ function homeUrl(home) {
19086
+ return `https://github.com/${homeRepository(home)}`;
19087
+ }
19088
+ function identityRegex(home) {
19089
+ return `^https://github.com/${homeRepository(home)}/\\.github/workflows/release\\.yaml@refs/tags/cli-v`;
19090
+ }
19091
+ function releaseHomeFor(version) {
19058
19092
  if (!VERSION.test(version))
19059
19093
  throw new Error(`invalid release version: ${version}`);
19060
- return `https://github.com/candledottv/agentic/.github/workflows/release.yaml@refs/tags/cli-v${version}`;
19094
+ return compareVersions(version, BRIDGE_VERSION) <= 0 ? "legacy" : "current";
19095
+ }
19096
+ function updateHomeFor(current) {
19097
+ return compareVersions(current, BRIDGE_VERSION) < 0 ? "legacy" : "current";
19098
+ }
19099
+ function releaseIdentityUri(version) {
19100
+ const home = releaseHomeFor(version);
19101
+ return `https://github.com/${homeRepository(home)}/.github/workflows/release.yaml@refs/tags/cli-v${version}`;
19102
+ }
19103
+ function versionOfTag(tag) {
19104
+ const match = /^cli-v(\d+\.\d+\.\d+)$/.exec(tag);
19105
+ return match ? match[1] ?? null : null;
19061
19106
  }
19062
19107
  function compareVersions(a, b) {
19063
19108
  const pa = a.split(".").map((n) => Number.parseInt(n, 10) || 0);
@@ -19107,8 +19152,14 @@ async function fetchLatest(deps, baseUrl) {
19107
19152
  message: `Could not reach ${latestUrl(baseUrl)}: ${error instanceof Error ? error.message : String(error)}`
19108
19153
  };
19109
19154
  }
19110
- if (!res.ok)
19111
- return { ok: false, kind: "unreachable", message: `${latestUrl(baseUrl)} answered ${res.status}` };
19155
+ if (!res.ok) {
19156
+ return {
19157
+ ok: false,
19158
+ kind: "unreachable",
19159
+ message: `${latestUrl(baseUrl)} answered ${res.status}`,
19160
+ status: res.status
19161
+ };
19162
+ }
19112
19163
  let body;
19113
19164
  try {
19114
19165
  body = await res.json();
@@ -19126,7 +19177,7 @@ async function fetchPinned(deps, base, tag) {
19126
19177
  try {
19127
19178
  const res = await deps.fetch(url, { redirect: "follow" });
19128
19179
  if (!res.ok)
19129
- return { ok: false, kind: "unreachable", message: `${url} answered ${res.status}` };
19180
+ return { ok: false, kind: "unreachable", message: `${url} answered ${res.status}`, status: res.status };
19130
19181
  const manifest = await res.json();
19131
19182
  const missing = [
19132
19183
  typeof manifest.version === "string" ? null : "version",
@@ -19145,13 +19196,39 @@ async function fetchPinned(deps, base, tag) {
19145
19196
  };
19146
19197
  }
19147
19198
  }
19148
- function releaseBaseUrl(env) {
19199
+ function releaseBaseUrl(env, home = "legacy") {
19149
19200
  const override = env.CANDLE_RELEASE_BASE_URL?.trim();
19150
- return override ? override.replace(/\/$/, "") : RELEASE_BASE_URL;
19201
+ return override ? override.replace(/\/$/, "") : homeUrl(home);
19151
19202
  }
19152
- var RELEASE_BASE_URL = "https://github.com/candledottv/agentic", RELEASE_ISSUER = "https://token.actions.githubusercontent.com", VERSION;
19203
+ function manifestHomeMismatch(manifest, home, pinnedTag) {
19204
+ let versionHome;
19205
+ try {
19206
+ versionHome = releaseHomeFor(manifest.version);
19207
+ } catch (error) {
19208
+ return error instanceof Error ? error.message : String(error);
19209
+ }
19210
+ if (manifest.tag !== `cli-v${manifest.version}`) {
19211
+ return `the manifest's tag ${manifest.tag} does not name its version ${manifest.version}`;
19212
+ }
19213
+ if (pinnedTag !== undefined && manifest.tag !== pinnedTag) {
19214
+ return `asked for ${pinnedTag}, the manifest describes ${manifest.tag}`;
19215
+ }
19216
+ if (versionHome !== home) {
19217
+ return `${manifest.version} is released from ${homeRepository(versionHome)}, not ${homeRepository(home)}`;
19218
+ }
19219
+ return null;
19220
+ }
19221
+ var VERSION, REPOSITORY, HOMES, BRIDGE_VERSION, LEGACY_RELEASE_REPOSITORY, CURRENT_RELEASE_REPOSITORY, RELEASE_ISSUER = "https://token.actions.githubusercontent.com", RELEASE_BASE_URL, RELEASE_IDENTITY_REGEX;
19153
19222
  var init_release = __esm(() => {
19223
+ init_release_homes();
19154
19224
  VERSION = /^\d+\.\d+\.\d+$/;
19225
+ REPOSITORY = /^candledottv\/[a-z0-9-]+$/;
19226
+ HOMES = parseReleaseHomes(release_homes_default);
19227
+ BRIDGE_VERSION = HOMES.bridgeVersion;
19228
+ LEGACY_RELEASE_REPOSITORY = HOMES.legacy;
19229
+ CURRENT_RELEASE_REPOSITORY = HOMES.current;
19230
+ RELEASE_BASE_URL = homeUrl("legacy");
19231
+ RELEASE_IDENTITY_REGEX = identityRegex("legacy");
19155
19232
  });
19156
19233
 
19157
19234
  // ../../node_modules/@noble/curves/esm/nist.js
@@ -70590,7 +70667,7 @@ init_render();
70590
70667
  init_secret_store();
70591
70668
 
70592
70669
  // src/version.ts
70593
- var CLI_VERSION = "0.11.40";
70670
+ var CLI_VERSION = "0.11.41";
70594
70671
 
70595
70672
  // src/commands/auth.ts
70596
70673
  init_keys_embedded_wallet();
@@ -80758,7 +80835,7 @@ async function doctor(args, ctx) {
80758
80835
  const method = detectInstall(deps.execPath, realExec);
80759
80836
  const installDetail = method === "binary" ? `binary at ${deps.execPath}` : method === "homebrew" ? `Homebrew (${realExec})` : `script (${deps.execPath}); update with npm`;
80760
80837
  rows.push({ check: "Install", state: "PASS", detail: installDetail });
80761
- const latest = await fetchLatest(deps, releaseBaseUrl(deps.env));
80838
+ const latest = await fetchLatest(deps, releaseBaseUrl(deps.env, updateHomeFor(CLI_VERSION)));
80762
80839
  const helper = await locateFido2Helper(deps);
80763
80840
  const declaredHelper = latest.ok && deps.platformKey ? latest.manifest.helpers?.[deps.platformKey] : undefined;
80764
80841
  if (helper.state === "ready") {
@@ -95746,7 +95823,7 @@ init_render();
95746
95823
  init_fido2();
95747
95824
  var SIGNATURE_VERIFIED = "signature verified (Sigstore, keyless; signer pinned to the release workflow)";
95748
95825
  var INSTALLER_LINE = "curl -fsSL https://candle.tv/install.sh | bash";
95749
- async function update(args, ctx) {
95826
+ async function update(args, ctx, current = CLI_VERSION) {
95750
95827
  let __stack = [];
95751
95828
  try {
95752
95829
  const { deps, json } = ctx;
@@ -95761,11 +95838,16 @@ async function update(args, ctx) {
95761
95838
  }
95762
95839
  const check = parsed.booleans.has("--check");
95763
95840
  const pinned = parsed.values["--to"];
95841
+ const pinnedVersion = pinned === undefined ? undefined : versionOfTag(pinned);
95842
+ if (pinned !== undefined && pinnedVersion === null) {
95843
+ writeUsageFailure(deps, `--to takes a release tag such as cli-v${current}, not ${pinned}`, json);
95844
+ return 2;
95845
+ }
95764
95846
  const realExec = await deps.realpath(deps.execPath).catch(() => deps.execPath);
95765
95847
  const method = detectInstall(deps.execPath, realExec);
95766
95848
  if (method === "homebrew") {
95767
95849
  if (json) {
95768
- const payload = { current: CLI_VERSION, latest: null, updated: false, path: realExec, method };
95850
+ const payload = { current, latest: null, updated: false, path: realExec, method };
95769
95851
  deps.stdout.write(`${JSON.stringify(payload)}
95770
95852
  `);
95771
95853
  } else {
@@ -95776,7 +95858,7 @@ async function update(args, ctx) {
95776
95858
  }
95777
95859
  if (method === "script") {
95778
95860
  if (json) {
95779
- const payload = { current: CLI_VERSION, latest: null, updated: false, path: realExec, method };
95861
+ const payload = { current, latest: null, updated: false, path: realExec, method };
95780
95862
  deps.stdout.write(`${JSON.stringify(payload)}
95781
95863
  `);
95782
95864
  } else {
@@ -95785,8 +95867,21 @@ async function update(args, ctx) {
95785
95867
  }
95786
95868
  return 0;
95787
95869
  }
95788
- const base2 = releaseBaseUrl(deps.env);
95870
+ const home = pinned && pinnedVersion ? releaseHomeFor(pinnedVersion) : updateHomeFor(current);
95871
+ const base2 = releaseBaseUrl(deps.env, home);
95789
95872
  const fetched = pinned ? await fetchPinned(deps, base2, pinned) : await fetchLatest(deps, base2);
95873
+ if (!fetched.ok && !pinned && fetched.status === 404 && compareVersions(current, BRIDGE_VERSION) === 0) {
95874
+ const message = `candle ${current} is the final release from ${homeRepository("legacy")}. Later releases come from ${homeRepository("current")}, which has not published one yet. Nothing was changed.`;
95875
+ if (json) {
95876
+ const payload = { current, latest: null, updated: false, path: realExec, pending: homeRepository("current") };
95877
+ deps.stdout.write(`${JSON.stringify(payload)}
95878
+ `);
95879
+ } else {
95880
+ deps.stdout.write(`${message}
95881
+ `);
95882
+ }
95883
+ return 0;
95884
+ }
95790
95885
  if (!fetched.ok) {
95791
95886
  const code = fetched.kind === "invalid" ? "MANIFEST_INVALID" : "UPDATE_UNREACHABLE";
95792
95887
  writeLocalFailure(deps, { code, message: fetched.message }, json);
@@ -95795,6 +95890,9 @@ async function update(args, ctx) {
95795
95890
  const target = fetched.manifest;
95796
95891
  let identityUri;
95797
95892
  try {
95893
+ const mismatch = manifestHomeMismatch(target, home, pinned);
95894
+ if (mismatch !== null)
95895
+ throw new Error(mismatch);
95798
95896
  identityUri = releaseIdentityUri(target.version);
95799
95897
  } catch (error) {
95800
95898
  writeLocalFailure(deps, {
@@ -95804,34 +95902,34 @@ async function update(args, ctx) {
95804
95902
  }, json);
95805
95903
  return 1;
95806
95904
  }
95807
- const order = compareVersions(CLI_VERSION, target.version);
95905
+ const order = compareVersions(current, target.version);
95808
95906
  if (check) {
95809
95907
  if (json) {
95810
- const payload = { current: CLI_VERSION, latest: target.version, updated: false, path: realExec };
95908
+ const payload = { current, latest: target.version, updated: false, path: realExec };
95811
95909
  deps.stdout.write(`${JSON.stringify(payload)}
95812
95910
  `);
95813
95911
  } else if (order < 0) {
95814
- deps.stdout.write(`candle ${CLI_VERSION}; ${target.version} available. Run: candle update
95912
+ deps.stdout.write(`candle ${current}; ${target.version} available. Run: candle update
95815
95913
  `);
95816
95914
  } else {
95817
- deps.stdout.write(`candle ${CLI_VERSION} is up to date (latest ${target.version})
95915
+ deps.stdout.write(`candle ${current} is up to date (latest ${target.version})
95818
95916
  `);
95819
95917
  }
95820
95918
  return 0;
95821
95919
  }
95822
95920
  if (order === 0 || order > 0 && !pinned) {
95823
95921
  if (json) {
95824
- const payload = { current: CLI_VERSION, latest: target.version, updated: false, path: realExec };
95922
+ const payload = { current, latest: target.version, updated: false, path: realExec };
95825
95923
  deps.stdout.write(`${JSON.stringify(payload)}
95826
95924
  `);
95827
95925
  } else {
95828
- deps.stdout.write(`candle ${CLI_VERSION} is up to date
95926
+ deps.stdout.write(`candle ${current} is up to date
95829
95927
  `);
95830
95928
  }
95831
95929
  return 0;
95832
95930
  }
95833
95931
  if (order > 0 && pinned)
95834
- deps.stderr.write(`Warning: ${target.version} is a downgrade from ${CLI_VERSION}
95932
+ deps.stderr.write(`Warning: ${target.version} is a downgrade from ${current}
95835
95933
  `);
95836
95934
  if (!deps.platformKey) {
95837
95935
  writeLocalFailure(deps, {
@@ -95871,7 +95969,7 @@ async function update(args, ctx) {
95871
95969
  const steps = __using(__stack, commandSteps(ctx), 0);
95872
95970
  if (!json) {
95873
95971
  const total = asset.size + (helperAsset?.size ?? 0);
95874
- deps.stderr.write(`Updating candle ${CLI_VERSION} -> ${target.version} (${formatBytes(total)})
95972
+ deps.stderr.write(`Updating candle ${current} -> ${target.version} (${formatBytes(total)})
95875
95973
  `);
95876
95974
  }
95877
95975
  steps.start("downloading SHA256SUMS");
@@ -95953,7 +96051,7 @@ async function update(args, ctx) {
95953
96051
  const helperReport2 = helper !== null ? { name: HELPER_NAME, updated: true } : null;
95954
96052
  if (json) {
95955
96053
  const payload = {
95956
- current: CLI_VERSION,
96054
+ current,
95957
96055
  latest: target.version,
95958
96056
  updated: true,
95959
96057
  path: realExec,
@@ -95962,7 +96060,7 @@ async function update(args, ctx) {
95962
96060
  deps.stdout.write(`${JSON.stringify(payload)}
95963
96061
  `);
95964
96062
  } else {
95965
- deps.stdout.write(`Updated candle ${CLI_VERSION} -> ${target.version}
96063
+ deps.stdout.write(`Updated candle ${current} -> ${target.version}
95966
96064
  `);
95967
96065
  if (helper !== null)
95968
96066
  deps.stdout.write(`Installed ${HELPER_NAME} ${target.version} to ${helper.target}
@@ -97194,7 +97292,8 @@ async function installHelperForThisRelease(ctx) {
97194
97292
  }
97195
97293
  if (!deps.platformKey)
97196
97294
  return { ok: false, message: "this CLI ships no security key helper for this platform" };
97197
- const base2 = releaseBaseUrl(deps.env);
97295
+ const home = releaseHomeFor(CLI_VERSION);
97296
+ const base2 = releaseBaseUrl(deps.env, home);
97198
97297
  const tag = `cli-v${CLI_VERSION}`;
97199
97298
  const name2 = helperAssetName(deps.platformKey);
97200
97299
  const steps = __using(__stack, commandSteps(ctx), 0);
@@ -97204,6 +97303,11 @@ async function installHelperForThisRelease(ctx) {
97204
97303
  steps.fail(`reading the ${tag} release manifest`);
97205
97304
  return { ok: false, message: fetched.message };
97206
97305
  }
97306
+ const mismatch = manifestHomeMismatch(fetched.manifest, home, tag);
97307
+ if (mismatch !== null) {
97308
+ steps.fail(`reading the ${tag} release manifest`);
97309
+ return { ok: false, message: `refusing the ${tag} release manifest: ${mismatch}` };
97310
+ }
97207
97311
  const asset = fetched.manifest.helpers?.[deps.platformKey];
97208
97312
  if (asset === undefined) {
97209
97313
  steps.fail(`reading the ${tag} release manifest`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@candledottv/cli",
3
- "version": "0.11.40",
3
+ "version": "0.11.41",
4
4
  "description": "The Candle CLI: authorize a device from your browser, then manage API keys, wallets, and setup health from the terminal",
5
5
  "type": "module",
6
6
  "bin": {