@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.js CHANGED
@@ -1,12 +1,86 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ cliVersion,
4
+ compareVersions,
3
5
  exitCodeFor,
4
6
  redactSecrets,
5
7
  runCli
6
- } from "./chunk-3YSCRXPF.js";
8
+ } from "./chunk-3SQ2XUBB.js";
9
+
10
+ // src/cli-update.ts
11
+ import { realpathSync } from "fs";
12
+ var DEFAULT_REGISTRY_URL = "https://registry.npmjs.org/@odla-ai%2fcli/latest";
13
+ var VERSION = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/;
14
+ async function requireCurrentCliForProvision(argv, options = {}) {
15
+ if (argv[0] !== "provision" || argv.includes("--dry-run")) return;
16
+ const current = options.currentVersion ?? cliVersion();
17
+ if (!VERSION.test(current)) return;
18
+ const latest = await fetchLatestCliVersion(options);
19
+ if (!latest || compareVersions(current, latest) >= 0) return;
20
+ const entryPath = resolvedEntryPath(options.entryPath ?? process.argv[1]);
21
+ const workspace = isWorkspaceCli(entryPath);
22
+ const rerun = renderReleasedProvisionCommand(latest, argv);
23
+ 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.";
24
+ throw new Error(
25
+ `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}
26
+ Run the current release now:
27
+ ${rerun}`
28
+ );
29
+ }
30
+ async function fetchLatestCliVersion(options) {
31
+ const controller = new AbortController();
32
+ const timeout = setTimeout(() => controller.abort(), options.timeoutMs ?? 2500);
33
+ timeout.unref?.();
34
+ try {
35
+ const response = await (options.fetch ?? fetch)(
36
+ options.registryUrl ?? process.env.ODLA_CLI_REGISTRY_URL ?? DEFAULT_REGISTRY_URL,
37
+ {
38
+ headers: {
39
+ accept: "application/json",
40
+ "user-agent": `odla-ai-cli/${options.currentVersion ?? cliVersion()}`
41
+ },
42
+ signal: controller.signal
43
+ }
44
+ );
45
+ if (!response.ok) return null;
46
+ const body = await response.json();
47
+ return typeof body.version === "string" && VERSION.test(body.version) ? body.version : null;
48
+ } catch {
49
+ return null;
50
+ } finally {
51
+ clearTimeout(timeout);
52
+ }
53
+ }
54
+ function resolvedEntryPath(entryPath) {
55
+ if (!entryPath) return "unknown executable";
56
+ try {
57
+ return realpathSync(entryPath);
58
+ } catch {
59
+ return entryPath;
60
+ }
61
+ }
62
+ function isWorkspaceCli(entryPath) {
63
+ const normalized = entryPath.replaceAll("\\", "/");
64
+ return normalized.includes("/packages/cli/dist/bin.") && !normalized.includes("/node_modules/");
65
+ }
66
+ function renderReleasedProvisionCommand(latest, argv) {
67
+ const safeArgs = [];
68
+ for (let index = 0; index < argv.length; index++) {
69
+ const value = argv[index];
70
+ safeArgs.push(value);
71
+ if (value === "--token" && index + 1 < argv.length) {
72
+ safeArgs.push("<redacted-token>");
73
+ index++;
74
+ }
75
+ }
76
+ return ["npx", "--yes", `@odla-ai/cli@${latest}`, ...safeArgs].map(shellQuote).join(" ");
77
+ }
78
+ function shellQuote(value) {
79
+ return /^[A-Za-z0-9_@%+=:,./-]+$/.test(value) ? value : `'${value.replaceAll("'", `'"'"'`)}'`;
80
+ }
7
81
 
8
82
  // src/bin.ts
9
- runCli().catch((err) => {
83
+ requireCurrentCliForProvision(process.argv.slice(2)).then(() => runCli()).catch((err) => {
10
84
  console.error(redactSecrets(`odla-ai: ${err instanceof Error ? err.message : String(err)}`));
11
85
  process.exitCode = exitCodeFor(err);
12
86
  });
package/dist/bin.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/bin.ts"],"sourcesContent":["import { exitCodeFor, runCli } from \"./cli\";\nimport { redactSecrets } from \"./redact\";\n\nrunCli().catch((err) => {\n console.error(redactSecrets(`odla-ai: ${err instanceof Error ? err.message : String(err)}`));\n process.exitCode = exitCodeFor(err);\n});\n"],"mappings":";;;;;;;;AAGA,OAAO,EAAE,MAAM,CAAC,QAAQ;AACtB,UAAQ,MAAM,cAAc,YAAY,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE,CAAC;AAC3F,UAAQ,WAAW,YAAY,GAAG;AACpC,CAAC;","names":[]}
1
+ {"version":3,"sources":["../src/cli-update.ts","../src/bin.ts"],"sourcesContent":["import { realpathSync } from \"node:fs\";\nimport { compareVersions } from \"./runbook-requires\";\nimport { cliVersion } from \"./version\";\n\nconst DEFAULT_REGISTRY_URL = \"https://registry.npmjs.org/@odla-ai%2fcli/latest\";\nconst VERSION = /^\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?$/;\n\nexport interface CliUpdateCheckOptions {\n currentVersion?: string;\n entryPath?: string;\n fetch?: typeof fetch;\n registryUrl?: string;\n timeoutMs?: number;\n}\n\n/**\n * Provisioning handshakes are security-sensitive protocol requests. Before a\n * real provision run, stop a CLI which is confirmed older than npm's current\n * release so an agent cannot unknowingly submit an obsolete grant shape.\n * Registry unavailability remains fail-open: npm must not become a production\n * availability dependency for an otherwise current CLI.\n */\nexport async function requireCurrentCliForProvision(\n argv: readonly string[],\n options: CliUpdateCheckOptions = {},\n): Promise<void> {\n if (argv[0] !== \"provision\" || argv.includes(\"--dry-run\")) return;\n\n const current = options.currentVersion ?? cliVersion();\n if (!VERSION.test(current)) return;\n const latest = await fetchLatestCliVersion(options);\n if (!latest || compareVersions(current, latest) >= 0) return;\n\n const entryPath = resolvedEntryPath(options.entryPath ?? process.argv[1]);\n const workspace = isWorkspaceCli(entryPath);\n const rerun = renderReleasedProvisionCommand(latest, argv);\n const source = workspace\n ? ` This executable resolves to the workspace build at ${entryPath}; update/rebase that worktree and rebuild it before using the linked CLI again.`\n : \" Update the installed dependency before using its CLI again.\";\n throw new Error(\n `provision blocked: @odla-ai/cli ${current} is older than the released ${latest}. ` +\n `Provisioning grant requests are security-sensitive, and a stale client can omit required authority.${source}\\n` +\n `Run the current release now:\\n ${rerun}`,\n );\n}\n\nasync function fetchLatestCliVersion(\n options: CliUpdateCheckOptions,\n): Promise<string | null> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), options.timeoutMs ?? 2_500);\n timeout.unref?.();\n try {\n const response = await (options.fetch ?? fetch)(\n options.registryUrl ?? process.env.ODLA_CLI_REGISTRY_URL ?? DEFAULT_REGISTRY_URL,\n {\n headers: {\n accept: \"application/json\",\n \"user-agent\": `odla-ai-cli/${options.currentVersion ?? cliVersion()}`,\n },\n signal: controller.signal,\n },\n );\n if (!response.ok) return null;\n const body = await response.json() as { version?: unknown };\n return typeof body.version === \"string\" && VERSION.test(body.version)\n ? body.version\n : null;\n } catch {\n return null;\n } finally {\n clearTimeout(timeout);\n }\n}\n\nfunction resolvedEntryPath(entryPath: string | undefined): string {\n if (!entryPath) return \"unknown executable\";\n try {\n return realpathSync(entryPath);\n } catch {\n return entryPath;\n }\n}\n\nfunction isWorkspaceCli(entryPath: string): boolean {\n const normalized = entryPath.replaceAll(\"\\\\\", \"/\");\n return normalized.includes(\"/packages/cli/dist/bin.\") &&\n !normalized.includes(\"/node_modules/\");\n}\n\nfunction renderReleasedProvisionCommand(\n latest: string,\n argv: readonly string[],\n): string {\n const safeArgs: string[] = [];\n for (let index = 0; index < argv.length; index++) {\n const value = argv[index]!;\n safeArgs.push(value);\n if (value === \"--token\" && index + 1 < argv.length) {\n safeArgs.push(\"<redacted-token>\");\n index++;\n }\n }\n return [\"npx\", \"--yes\", `@odla-ai/cli@${latest}`, ...safeArgs]\n .map(shellQuote)\n .join(\" \");\n}\n\nfunction shellQuote(value: string): string {\n return /^[A-Za-z0-9_@%+=:,./-]+$/.test(value)\n ? value\n : `'${value.replaceAll(\"'\", `'\"'\"'`)}'`;\n}\n","import { exitCodeFor, runCli } from \"./cli\";\nimport { requireCurrentCliForProvision } from \"./cli-update\";\nimport { redactSecrets } from \"./redact\";\n\nrequireCurrentCliForProvision(process.argv.slice(2))\n .then(() => runCli())\n .catch((err) => {\n console.error(redactSecrets(`odla-ai: ${err instanceof Error ? err.message : String(err)}`));\n process.exitCode = exitCodeFor(err);\n });\n"],"mappings":";;;;;;;;;;AAAA,SAAS,oBAAoB;AAI7B,IAAM,uBAAuB;AAC7B,IAAM,UAAU;AAiBhB,eAAsB,8BACpB,MACA,UAAiC,CAAC,GACnB;AACf,MAAI,KAAK,CAAC,MAAM,eAAe,KAAK,SAAS,WAAW,EAAG;AAE3D,QAAM,UAAU,QAAQ,kBAAkB,WAAW;AACrD,MAAI,CAAC,QAAQ,KAAK,OAAO,EAAG;AAC5B,QAAM,SAAS,MAAM,sBAAsB,OAAO;AAClD,MAAI,CAAC,UAAU,gBAAgB,SAAS,MAAM,KAAK,EAAG;AAEtD,QAAM,YAAY,kBAAkB,QAAQ,aAAa,QAAQ,KAAK,CAAC,CAAC;AACxE,QAAM,YAAY,eAAe,SAAS;AAC1C,QAAM,QAAQ,+BAA+B,QAAQ,IAAI;AACzD,QAAM,SAAS,YACX,uDAAuD,SAAS,oFAChE;AACJ,QAAM,IAAI;AAAA,IACR,mCAAmC,OAAO,+BAA+B,MAAM,wGACuB,MAAM;AAAA;AAAA,IACzE,KAAK;AAAA,EAC1C;AACF;AAEA,eAAe,sBACb,SACwB;AACxB,QAAM,aAAa,IAAI,gBAAgB;AACvC,QAAM,UAAU,WAAW,MAAM,WAAW,MAAM,GAAG,QAAQ,aAAa,IAAK;AAC/E,UAAQ,QAAQ;AAChB,MAAI;AACF,UAAM,WAAW,OAAO,QAAQ,SAAS;AAAA,MACvC,QAAQ,eAAe,QAAQ,IAAI,yBAAyB;AAAA,MAC5D;AAAA,QACE,SAAS;AAAA,UACP,QAAQ;AAAA,UACR,cAAc,eAAe,QAAQ,kBAAkB,WAAW,CAAC;AAAA,QACrE;AAAA,QACA,QAAQ,WAAW;AAAA,MACrB;AAAA,IACF;AACA,QAAI,CAAC,SAAS,GAAI,QAAO;AACzB,UAAM,OAAO,MAAM,SAAS,KAAK;AACjC,WAAO,OAAO,KAAK,YAAY,YAAY,QAAQ,KAAK,KAAK,OAAO,IAChE,KAAK,UACL;AAAA,EACN,QAAQ;AACN,WAAO;AAAA,EACT,UAAE;AACA,iBAAa,OAAO;AAAA,EACtB;AACF;AAEA,SAAS,kBAAkB,WAAuC;AAChE,MAAI,CAAC,UAAW,QAAO;AACvB,MAAI;AACF,WAAO,aAAa,SAAS;AAAA,EAC/B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,eAAe,WAA4B;AAClD,QAAM,aAAa,UAAU,WAAW,MAAM,GAAG;AACjD,SAAO,WAAW,SAAS,yBAAyB,KAClD,CAAC,WAAW,SAAS,gBAAgB;AACzC;AAEA,SAAS,+BACP,QACA,MACQ;AACR,QAAM,WAAqB,CAAC;AAC5B,WAAS,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS;AAChD,UAAM,QAAQ,KAAK,KAAK;AACxB,aAAS,KAAK,KAAK;AACnB,QAAI,UAAU,aAAa,QAAQ,IAAI,KAAK,QAAQ;AAClD,eAAS,KAAK,kBAAkB;AAChC;AAAA,IACF;AAAA,EACF;AACA,SAAO,CAAC,OAAO,SAAS,gBAAgB,MAAM,IAAI,GAAG,QAAQ,EAC1D,IAAI,UAAU,EACd,KAAK,GAAG;AACb;AAEA,SAAS,WAAW,OAAuB;AACzC,SAAO,2BAA2B,KAAK,KAAK,IACxC,QACA,IAAI,MAAM,WAAW,KAAK,OAAO,CAAC;AACxC;;;AC5GA,8BAA8B,QAAQ,KAAK,MAAM,CAAC,CAAC,EAChD,KAAK,MAAM,OAAO,CAAC,EACnB,MAAM,CAAC,QAAQ;AACd,UAAQ,MAAM,cAAc,YAAY,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE,CAAC;AAC3F,UAAQ,WAAW,YAAY,GAAG;AACpC,CAAC;","names":[]}
@@ -9517,6 +9517,9 @@ Safety:
9517
9517
  grant, run it once with --request-grant. That flag ignores ODLA_DEV_TOKEN and
9518
9518
  the local cache, prints and opens a fresh exact-project owner-review URL, then
9519
9519
  continues provisioning with the approved replacement credential.
9520
+ Before a non-dry-run provision, the executable checks npm's current CLI
9521
+ release. A confirmed stale client stops with a safe npx rerun command; a
9522
+ workspace-linked client also identifies the worktree that must be updated.
9520
9523
  Run Code from a GitHub checkout already connected to an app in Studio; an
9521
9524
  odla.config.mjs may select the app explicitly but is not required. Code host
9522
9525
  approval and credential hashes live in odla-ai/db. The host
@@ -12885,6 +12888,7 @@ export {
12885
12888
  calendarDisconnect,
12886
12889
  CAPABILITIES,
12887
12890
  printCapabilities,
12891
+ cliVersion,
12888
12892
  ConfigOperationCommandError,
12889
12893
  desiredRegistryState,
12890
12894
  configApply,
@@ -12918,6 +12922,7 @@ export {
12918
12922
  describeProblem,
12919
12923
  invocationPath,
12920
12924
  surfacePaths,
12925
+ compareVersions,
12921
12926
  runHostedSecurity,
12922
12927
  getHostedSecurityIntent,
12923
12928
  getHostedSecurityPlan,
@@ -12930,4 +12935,4 @@ export {
12930
12935
  exitCodeFor,
12931
12936
  runCli
12932
12937
  };
12933
- //# sourceMappingURL=chunk-3YSCRXPF.js.map
12938
+ //# sourceMappingURL=chunk-3SQ2XUBB.js.map