@odla-ai/cli 0.27.13 → 0.27.14

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/bin.cjs CHANGED
@@ -8663,6 +8663,9 @@ Safety:
8663
8663
  grant, run it once with --request-grant. That flag ignores ODLA_DEV_TOKEN and
8664
8664
  the local cache, prints and opens a fresh exact-project owner-review URL, then
8665
8665
  continues provisioning with the approved replacement credential.
8666
+ Before a non-dry-run provision, the executable checks npm's current CLI
8667
+ release. A confirmed stale client stops with a safe npx rerun command; a
8668
+ workspace-linked client also identifies the worktree that must be updated.
8666
8669
  Run Code from a GitHub checkout already connected to an app in Studio; an
8667
8670
  odla.config.mjs may select the app explicitly but is not required. Code host
8668
8671
  approval and credential hashes live in odla-ai/db. The host
@@ -12798,8 +12801,80 @@ async function calendarCommand(parsed, dependencies) {
12798
12801
  else await calendarDisconnect(options);
12799
12802
  }
12800
12803
 
12804
+ // src/cli-update.ts
12805
+ var import_node_fs20 = require("fs");
12806
+ var DEFAULT_REGISTRY_URL = "https://registry.npmjs.org/@odla-ai%2fcli/latest";
12807
+ var VERSION = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/;
12808
+ async function requireCurrentCliForProvision(argv, options = {}) {
12809
+ if (argv[0] !== "provision" || argv.includes("--dry-run")) return;
12810
+ const current = options.currentVersion ?? cliVersion();
12811
+ if (!VERSION.test(current)) return;
12812
+ const latest = await fetchLatestCliVersion(options);
12813
+ if (!latest || compareVersions(current, latest) >= 0) return;
12814
+ const entryPath = resolvedEntryPath(options.entryPath ?? process.argv[1]);
12815
+ const workspace = isWorkspaceCli(entryPath);
12816
+ const rerun = renderReleasedProvisionCommand(latest, argv);
12817
+ const source = workspace ? ` This executable resolves to the workspace build at ${entryPath}; update/rebase that worktree and rebuild it before using the linked CLI again.` : " Update the installed dependency before using its CLI again.";
12818
+ throw new Error(
12819
+ `provision blocked: @odla-ai/cli ${current} is older than the released ${latest}. Provisioning grant requests are security-sensitive, and a stale client can omit required authority.${source}
12820
+ Run the current release now:
12821
+ ${rerun}`
12822
+ );
12823
+ }
12824
+ async function fetchLatestCliVersion(options) {
12825
+ const controller = new AbortController();
12826
+ const timeout = setTimeout(() => controller.abort(), options.timeoutMs ?? 2500);
12827
+ timeout.unref?.();
12828
+ try {
12829
+ const response2 = await (options.fetch ?? fetch)(
12830
+ options.registryUrl ?? process.env.ODLA_CLI_REGISTRY_URL ?? DEFAULT_REGISTRY_URL,
12831
+ {
12832
+ headers: {
12833
+ accept: "application/json",
12834
+ "user-agent": `odla-ai-cli/${options.currentVersion ?? cliVersion()}`
12835
+ },
12836
+ signal: controller.signal
12837
+ }
12838
+ );
12839
+ if (!response2.ok) return null;
12840
+ const body = await response2.json();
12841
+ return typeof body.version === "string" && VERSION.test(body.version) ? body.version : null;
12842
+ } catch {
12843
+ return null;
12844
+ } finally {
12845
+ clearTimeout(timeout);
12846
+ }
12847
+ }
12848
+ function resolvedEntryPath(entryPath) {
12849
+ if (!entryPath) return "unknown executable";
12850
+ try {
12851
+ return (0, import_node_fs20.realpathSync)(entryPath);
12852
+ } catch {
12853
+ return entryPath;
12854
+ }
12855
+ }
12856
+ function isWorkspaceCli(entryPath) {
12857
+ const normalized = entryPath.replaceAll("\\", "/");
12858
+ return normalized.includes("/packages/cli/dist/bin.") && !normalized.includes("/node_modules/");
12859
+ }
12860
+ function renderReleasedProvisionCommand(latest, argv) {
12861
+ const safeArgs = [];
12862
+ for (let index = 0; index < argv.length; index++) {
12863
+ const value2 = argv[index];
12864
+ safeArgs.push(value2);
12865
+ if (value2 === "--token" && index + 1 < argv.length) {
12866
+ safeArgs.push("<redacted-token>");
12867
+ index++;
12868
+ }
12869
+ }
12870
+ return ["npx", "--yes", `@odla-ai/cli@${latest}`, ...safeArgs].map(shellQuote).join(" ");
12871
+ }
12872
+ function shellQuote(value2) {
12873
+ return /^[A-Za-z0-9_@%+=:,./-]+$/.test(value2) ? value2 : `'${value2.replaceAll("'", `'"'"'`)}'`;
12874
+ }
12875
+
12801
12876
  // src/bin.ts
12802
- runCli().catch((err) => {
12877
+ requireCurrentCliForProvision(process.argv.slice(2)).then(() => runCli()).catch((err) => {
12803
12878
  console.error(redactSecrets(`odla-ai: ${err instanceof Error ? err.message : String(err)}`));
12804
12879
  process.exitCode = exitCodeFor(err);
12805
12880
  });