@odla-ai/cli 0.20.2 → 0.22.0

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
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  exitCodeFor,
4
4
  runCli
5
- } from "./chunk-XBPDHNWO.js";
5
+ } from "./chunk-DINDRUDA.js";
6
6
 
7
7
  // src/bin.ts
8
8
  runCli().catch((err) => {
@@ -179,7 +179,7 @@ function approvalLines(prompt) {
179
179
  return lines;
180
180
  }
181
181
  function printApproval(out, prompt) {
182
- for (const line of approvalLines(prompt)) out.log(line);
182
+ for (const line of approvalLines(prompt)) out.error(line);
183
183
  }
184
184
  function reminderLines(prompt) {
185
185
  return [
@@ -251,7 +251,7 @@ async function getDeveloperToken(cfg, options, doFetch, out) {
251
251
  }
252
252
  const cached = readJsonFile(cfg.local.tokenFile);
253
253
  if (cached?.token && cached.platform === audience && (cached.expiresAt ?? 0) > Date.now() + 6e4) {
254
- out.log(`auth: using cached developer token (${displayPath(cfg.local.tokenFile, cfg.rootDir)})`);
254
+ out.error(`auth: using cached developer token (${displayPath(cfg.local.tokenFile, cfg.rootDir)})`);
255
255
  return cached.token;
256
256
  }
257
257
  const ctx = {
@@ -268,16 +268,16 @@ async function getDeveloperToken(cfg, options, doFetch, out) {
268
268
  const { token, expiresAt } = await resumePendingHandshake(ctx, waitMs) ?? await freshHandshake(ctx, waitMs);
269
269
  clearPendingHandshake(ctx.pendingFile);
270
270
  writePrivateJson(cfg.local.tokenFile, { platform: audience, email: ctx.email, token, expiresAt });
271
- out.log(`auth: developer token cached (${displayPath(cfg.local.tokenFile, cfg.rootDir)})`);
271
+ out.error(`auth: developer token cached (${displayPath(cfg.local.tokenFile, cfg.rootDir)})`);
272
272
  return token;
273
273
  }
274
274
  async function resumePendingHandshake(ctx, waitMs) {
275
275
  const pending = readPendingHandshake(ctx.pendingFile, ctx.audience, ctx.email);
276
276
  if (!pending) return null;
277
- ctx.out.log("");
278
- ctx.out.log(`auth: resuming pending handshake \u2014 ${approvalHint(pending)}`);
277
+ ctx.out.error("");
278
+ ctx.out.error(`auth: resuming pending handshake \u2014 ${approvalHint(pending)}`);
279
279
  await launchApproval(ctx, pending.approvalUrl);
280
- ctx.out.log("");
280
+ ctx.out.error("");
281
281
  const stopReminder = approvalReminder(ctx.out, pending);
282
282
  try {
283
283
  return await collectToken({
@@ -293,7 +293,7 @@ async function resumePendingHandshake(ctx, waitMs) {
293
293
  if (code === "handshake_pending") throw stillPending(pending, ctx.email);
294
294
  if (code === "handshake_expired" || code === "handshake_timeout") {
295
295
  clearPendingHandshake(ctx.pendingFile);
296
- ctx.out.log("auth: pending handshake lapsed unapproved; starting a fresh one");
296
+ ctx.out.error("auth: pending handshake lapsed unapproved; starting a fresh one");
297
297
  return null;
298
298
  }
299
299
  if (code === "handshake_denied") clearPendingHandshake(ctx.pendingFile);
@@ -351,12 +351,12 @@ async function launchApproval(ctx, approvalUrl) {
351
351
  if (ctx.browser.open) {
352
352
  try {
353
353
  await (ctx.options.openApprovalUrl ?? openUrl)(approvalUrl);
354
- ctx.out.log(`auth: asked the OS to open a browser${ctx.browser.mode === "auto" ? " (auto)" : ""} \u2014 if no tab appeared, use the URL above`);
354
+ ctx.out.error(`auth: asked the OS to open a browser${ctx.browser.mode === "auto" ? " (auto)" : ""} \u2014 if no tab appeared, use the URL above`);
355
355
  } catch (err) {
356
- ctx.out.log(`auth: could not open browser (${err instanceof Error ? err.message : String(err)})`);
356
+ ctx.out.error(`auth: could not open browser (${err instanceof Error ? err.message : String(err)})`);
357
357
  }
358
358
  } else if (ctx.browser.reason) {
359
- ctx.out.log(`auth: browser launch skipped (${ctx.browser.reason}) \u2014 show the human the URL above`);
359
+ ctx.out.error(`auth: browser launch skipped (${ctx.browser.reason}) \u2014 show the human the URL above`);
360
360
  }
361
361
  }
362
362
  function stillPending(pending, email) {
@@ -454,7 +454,7 @@ async function scopedToken(platform, scope, options, doFetch, out) {
454
454
  const cache = options.cache === false ? null : readJsonFile(tokenFile);
455
455
  const cached = cache?.platform === audience ? cache.tokens?.[scope] : void 0;
456
456
  if (cached?.token && (cached.expiresAt ?? 0) > Date.now() + 6e4) {
457
- out.log(`auth: using cached ${scope} grant (${tokenFile})`);
457
+ out.error(`auth: using cached ${scope} grant (${tokenFile})`);
458
458
  return cached.token;
459
459
  }
460
460
  const email = handshakeEmail(options.email, cache?.platform === audience ? cache.email : void 0);
@@ -485,9 +485,9 @@ async function scopedToken(platform, scope, options, doFetch, out) {
485
485
  tokens[scope] = { token, expiresAt };
486
486
  if (existsSync2(join2(rootDir, ".git"))) ensureGitignore(rootDir, [tokenFile]);
487
487
  writePrivateJson(tokenFile, { platform: audience, email, tokens });
488
- out.log(`auth: cached ${scope} grant (${tokenFile}; mode 0600)`);
488
+ out.error(`auth: cached ${scope} grant (${tokenFile}; mode 0600)`);
489
489
  } else {
490
- out.log(`auth: ${scope} grant is in memory only; its credential record remains in odla-ai/db`);
490
+ out.error(`auth: ${scope} grant is in memory only; its credential record remains in odla-ai/db`);
491
491
  }
492
492
  return token;
493
493
  }
@@ -6844,6 +6844,18 @@ function describeProblem(problem) {
6844
6844
  const where = problem.validPrefix ? `after "${problem.validPrefix}"` : "as a command";
6845
6845
  return `"${problem.word}" is not accepted ${where} \u2014 try: ${problem.accepted.join(", ")}`;
6846
6846
  }
6847
+ function invocationPath(words2) {
6848
+ let node = COMMAND_SURFACE;
6849
+ const path = [];
6850
+ for (const word of words2) {
6851
+ const next = node[word];
6852
+ if (!next) break;
6853
+ path.push(word);
6854
+ node = next;
6855
+ if (Object.keys(node).length === 0) break;
6856
+ }
6857
+ return path;
6858
+ }
6847
6859
  function surfacePaths(node = COMMAND_SURFACE, prefix = []) {
6848
6860
  const paths = [];
6849
6861
  for (const [word, child] of Object.entries(node)) {
@@ -8167,10 +8179,28 @@ async function pmCommand(parsed, deps = {}) {
8167
8179
  }
8168
8180
  }
8169
8181
 
8182
+ // src/record.ts
8183
+ import { appendFileSync } from "fs";
8184
+ import process9 from "process";
8185
+ function recordInvocation(parsed) {
8186
+ const file = process9.env.ODLA_CLI_RECORD;
8187
+ if (!file) return;
8188
+ try {
8189
+ const entry = {
8190
+ path: invocationPath(parsed.positionals),
8191
+ options: Object.keys(parsed.options).sort()
8192
+ };
8193
+ if (!entry.path.length) return;
8194
+ appendFileSync(file, `${JSON.stringify(entry)}
8195
+ `);
8196
+ } catch {
8197
+ }
8198
+ }
8199
+
8170
8200
  // src/runbook-command.ts
8171
8201
  import { existsSync as existsSync10 } from "fs";
8172
8202
  import { join as join12, resolve as resolve10 } from "path";
8173
- import process10 from "process";
8203
+ import process11 from "process";
8174
8204
 
8175
8205
  // src/runbook-actions.ts
8176
8206
  import { readFileSync as readFileSync8 } from "fs";
@@ -8824,9 +8854,9 @@ import { spawnSync } from "child_process";
8824
8854
  import { mkdtempSync, readFileSync as readFileSync11, rmSync as rmSync2, writeFileSync as writeFileSync4 } from "fs";
8825
8855
  import { tmpdir as tmpdir4 } from "os";
8826
8856
  import { join as join11 } from "path";
8827
- import process9 from "process";
8857
+ import process10 from "process";
8828
8858
  var EDITOR_ENV = ["ODLA_EDITOR", "VISUAL", "EDITOR"];
8829
- function resolveEditor(env = process9.env) {
8859
+ function resolveEditor(env = process10.env) {
8830
8860
  for (const name of EDITOR_ENV) {
8831
8861
  const value = env[name];
8832
8862
  if (value && value.trim()) return value.trim();
@@ -8840,8 +8870,8 @@ function defaultRun(command, path) {
8840
8870
  return result.status ?? 0;
8841
8871
  }
8842
8872
  function editText(initial, slug, deps = {}) {
8843
- const env = deps.env ?? process9.env;
8844
- const interactive = deps.interactive ?? (() => Boolean(process9.stdin.isTTY));
8873
+ const env = deps.env ?? process10.env;
8874
+ const interactive = deps.interactive ?? (() => Boolean(process10.stdin.isTTY));
8845
8875
  const editor = resolveEditor(env);
8846
8876
  if (!editor)
8847
8877
  throw new Error(
@@ -8959,10 +8989,10 @@ var CONFIG_FREE = /* @__PURE__ */ new Set(["list", "search", "ask", "get", "cat"
8959
8989
  async function loadOrDefaultConfig(configPath, action, appId) {
8960
8990
  const projectScoped = appId !== void 0;
8961
8991
  if (!projectScoped && CONFIG_FREE.has(action) && !existsSync10(resolve10(configPath))) {
8962
- const rootDir = process10.cwd();
8992
+ const rootDir = process11.cwd();
8963
8993
  return {
8964
8994
  configPath,
8965
- platformUrl: process10.env.ODLA_PLATFORM_URL ?? "https://odla.ai",
8995
+ platformUrl: process11.env.ODLA_PLATFORM_URL ?? "https://odla.ai",
8966
8996
  rootDir,
8967
8997
  app: { id: "", name: "" },
8968
8998
  local: { tokenFile: join12(rootDir, ".odla/dev-token.json") }
@@ -8970,13 +9000,11 @@ async function loadOrDefaultConfig(configPath, action, appId) {
8970
9000
  }
8971
9001
  return loadProjectConfig(configPath);
8972
9002
  }
8973
- var PURE_STDOUT = /* @__PURE__ */ new Set(["get", "cat"]);
8974
9003
  async function buildContext2(parsed, deps, action) {
8975
9004
  const configPath = stringOpt(parsed.options.config) ?? "odla.config.mjs";
8976
9005
  const cfg = await loadOrDefaultConfig(configPath, action, stringOpt(parsed.options.app));
8977
9006
  const doFetch = deps.fetch ?? fetch;
8978
9007
  const out = deps.stdout ?? console;
8979
- const authOut = PURE_STDOUT.has(action) ? { log: (line) => out.error(line), error: (line) => out.error(line) } : out;
8980
9008
  const appId = stringOpt(parsed.options.app) ?? PLATFORM_SCOPE;
8981
9009
  const dryRun = parsed.options["dry-run"] === true;
8982
9010
  if (action === "import" && dryRun) {
@@ -8996,7 +9024,7 @@ async function buildContext2(parsed, deps, action) {
8996
9024
  email: stringOpt(parsed.options.email),
8997
9025
  label: `odla CLI (runbook ${action})`,
8998
9026
  fetch: doFetch,
8999
- stdout: authOut,
9027
+ stdout: out,
9000
9028
  openApprovalUrl: deps.openUrl,
9001
9029
  // Anchor the grant cache to this project, not the shell's cwd.
9002
9030
  rootDir: cfg.rootDir
@@ -9013,7 +9041,7 @@ async function buildContext2(parsed, deps, action) {
9013
9041
  open: void 0
9014
9042
  },
9015
9043
  doFetch,
9016
- authOut
9044
+ out
9017
9045
  );
9018
9046
  return {
9019
9047
  platformUrl: cfg.platformUrl,
@@ -9556,6 +9584,7 @@ function exitCodeFor(err) {
9556
9584
  }
9557
9585
  async function runCli(argv = process.argv.slice(2), dependencies = {}) {
9558
9586
  const parsed = parseArgv(argv);
9587
+ recordInvocation(parsed);
9559
9588
  const command = parsed.positionals[0] ?? "help";
9560
9589
  if (command === "version" || command === "-v" || parsed.options.version === true) {
9561
9590
  assertArgs(parsed, ["version"], 1);
@@ -9704,6 +9733,7 @@ export {
9704
9733
  acceptedAfter,
9705
9734
  validateInvocation,
9706
9735
  describeProblem,
9736
+ invocationPath,
9707
9737
  surfacePaths,
9708
9738
  runHostedSecurity,
9709
9739
  getHostedSecurityIntent,
@@ -9717,4 +9747,4 @@ export {
9717
9747
  exitCodeFor,
9718
9748
  runCli
9719
9749
  };
9720
- //# sourceMappingURL=chunk-XBPDHNWO.js.map
9750
+ //# sourceMappingURL=chunk-DINDRUDA.js.map