@odla-ai/cli 0.10.2 → 0.11.1

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,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runCli
4
- } from "./chunk-MWVKOIGR.js";
4
+ } from "./chunk-DC4MIB4X.js";
5
5
 
6
6
  // src/bin.ts
7
7
  runCli().catch((err) => {
@@ -210,12 +210,16 @@ function handshakeEmail(value, cached) {
210
210
  }
211
211
  return email;
212
212
  }
213
- function approvalBrowser(options) {
213
+ function approvalBrowser(options, host = {}) {
214
214
  if (options.open === true) return { open: true, mode: "forced" };
215
215
  if (options.open === false) return { open: false, reason: "disabled by --no-open" };
216
- if (process3.env.CI) return { open: false, reason: "CI environment" };
217
- const interactive = options.interactive ?? Boolean(process3.stdin.isTTY && process3.stdout.isTTY);
218
- if (!interactive) return { open: false, reason: "non-interactive shell; pass --open to force" };
216
+ const env = host.env ?? process3.env;
217
+ if (env.CI) return { open: false, reason: "CI environment" };
218
+ if (env.SSH_CONNECTION || env.SSH_TTY) return { open: false, reason: "SSH session; pass --open to force" };
219
+ const platform = host.platform ?? process3.platform;
220
+ if (platform !== "darwin" && platform !== "win32" && !env.DISPLAY && !env.WAYLAND_DISPLAY) {
221
+ return { open: false, reason: "no graphical display; pass --open to force" };
222
+ }
219
223
  return { open: true, mode: "auto" };
220
224
  }
221
225
  function handshakeUrl(platformUrl, userCode) {
@@ -286,8 +290,9 @@ async function scopedToken(platform, scope, options, doFetch, out) {
286
290
  onCode: async ({ userCode, expiresIn, verificationUriComplete }) => {
287
291
  const approvalUrl = verificationUriComplete ?? handshakeUrl(audience, userCode);
288
292
  out.log(`Review, then approve scoped request ${userCode} at ${approvalUrl} within ${Math.floor(expiresIn / 60)}m.`);
289
- const shouldOpen = options.open === true || options.open !== false && !process4.env.CI && Boolean(process4.stdin.isTTY && process4.stdout.isTTY);
290
- if (shouldOpen) await (options.openApprovalUrl ?? openUrl)(approvalUrl).catch(() => void 0);
293
+ if (approvalBrowser({ open: options.open }).open) {
294
+ await (options.openApprovalUrl ?? openUrl)(approvalUrl).catch(() => void 0);
295
+ }
291
296
  }
292
297
  });
293
298
  const tokens = cache?.platform === audience ? { ...cache.tokens ?? {} } : {};
@@ -940,6 +945,28 @@ function looksSecret(value) {
940
945
  return redactSecrets(value) !== value || value.includes("-----BEGIN");
941
946
  }
942
947
 
948
+ // src/calendar-errors.ts
949
+ var PLATFORM_NOT_READY_CODES = /* @__PURE__ */ new Set([
950
+ "calendar_google_oauth_not_configured",
951
+ "calendar_token_vault_not_configured",
952
+ "calendar_db_ingress_not_configured"
953
+ ]);
954
+ var CalendarRequestError = class extends Error {
955
+ /** HTTP status returned by the registry. */
956
+ status;
957
+ /** Machine-readable `error.code` from the response body, when present. */
958
+ code;
959
+ constructor(message, status, code) {
960
+ super(message);
961
+ this.name = "CalendarRequestError";
962
+ this.status = status;
963
+ if (code !== void 0) this.code = code;
964
+ }
965
+ };
966
+ function isCalendarPlatformNotReady(error) {
967
+ return error instanceof CalendarRequestError && error.code !== void 0 && PLATFORM_NOT_READY_CODES.has(error.code);
968
+ }
969
+
943
970
  // src/calendar-http.ts
944
971
  var CALENDAR_STATES = [
945
972
  "not_connected",
@@ -1086,7 +1113,8 @@ async function calendarJson(ctx, suffix, init) {
1086
1113
  if (!response.ok) {
1087
1114
  const code = textField(body.error?.code, 128);
1088
1115
  const message = textField(body.error?.message, 500);
1089
- throw new Error(redactSecrets(`calendar request failed (${response.status})${code ? ` ${code}` : ""}${message ? `: ${message}` : ""}`));
1116
+ const detail = `${code ? ` ${code}` : ""}${message ? `: ${message}` : ""}`;
1117
+ throw new CalendarRequestError(redactSecrets(`calendar request failed (${response.status})${detail}`), response.status, code);
1090
1118
  }
1091
1119
  return body;
1092
1120
  }
@@ -1226,7 +1254,6 @@ async function lifecycleContext(options) {
1226
1254
  token: options.token,
1227
1255
  email: options.email,
1228
1256
  open: options.open,
1229
- interactive: options.interactive,
1230
1257
  openApprovalUrl: options.openConsentUrl
1231
1258
  },
1232
1259
  doFetch,
@@ -1235,7 +1262,7 @@ async function lifecycleContext(options) {
1235
1262
  return { cfg, ctx: { platform: cfg.platformUrl, appId: cfg.app.id, env, token, fetch: doFetch }, out };
1236
1263
  }
1237
1264
  function connectionOptions(options, out) {
1238
- const browser = approvalBrowser({ configPath: "odla.config.mjs", open: options.open, interactive: options.interactive });
1265
+ const browser = approvalBrowser({ open: options.open });
1239
1266
  return {
1240
1267
  out,
1241
1268
  open: browser.open,
@@ -2032,17 +2059,6 @@ async function provision(options) {
2032
2059
  if (cfg.services.includes("calendar")) {
2033
2060
  const calendarCtx = { platform: cfg.platformUrl, appId: cfg.app.id, env, token, fetch: doFetch };
2034
2061
  await applyCalendarBookingPage(calendarCtx, calendarBookingPageUrl(cfg, env), out);
2035
- await ensureCalendarConnected(
2036
- calendarCtx,
2037
- {
2038
- open: options.open,
2039
- interactive: options.interactive,
2040
- openConsentUrl: options.openApprovalUrl,
2041
- wait: options.calendarPollWait,
2042
- pollTimeoutMs: options.calendarPollTimeoutMs,
2043
- stdout: out
2044
- }
2045
- );
2046
2062
  }
2047
2063
  }
2048
2064
  for (const env of cfg.envs) {
@@ -2106,6 +2122,25 @@ ${env}: credentials are already saved; retry "odla-ai secrets push --env ${env}$
2106
2122
  writeDevVars(devVarsTarget, credentials, env, o11yDevVars(cfg));
2107
2123
  out.log(`dev vars: wrote ${displayPath(devVarsTarget, cfg.rootDir)} for ${env}`);
2108
2124
  }
2125
+ if (cfg.services.includes("calendar")) {
2126
+ for (const env of cfg.envs) {
2127
+ try {
2128
+ await ensureCalendarConnected(
2129
+ { platform: cfg.platformUrl, appId: cfg.app.id, env, token, fetch: doFetch },
2130
+ {
2131
+ open: options.open,
2132
+ openConsentUrl: options.openApprovalUrl,
2133
+ wait: options.calendarPollWait,
2134
+ pollTimeoutMs: options.calendarPollTimeoutMs,
2135
+ stdout: out
2136
+ }
2137
+ );
2138
+ } catch (error) {
2139
+ if (!isCalendarPlatformNotReady(error)) throw error;
2140
+ out.log(`${env}: calendar consent skipped (${error.code}); resume with "odla-ai calendar connect --env ${env}" once the platform is configured`);
2141
+ }
2142
+ }
2143
+ }
2109
2144
  }
2110
2145
  function serviceRank(service) {
2111
2146
  if (service === "db") return 0;
@@ -2987,7 +3022,6 @@ async function smoke(options) {
2987
3022
  token: options.token,
2988
3023
  email: options.email,
2989
3024
  open: options.open,
2990
- interactive: options.interactive,
2991
3025
  openApprovalUrl: options.openApprovalUrl
2992
3026
  },
2993
3027
  doFetch,
@@ -3275,8 +3309,9 @@ Safety:
3275
3309
  Provision caches the approved developer token and service credentials under
3276
3310
  .odla/ with mode 0600, and init adds those paths to .gitignore. Secret push
3277
3311
  preflights Wrangler before any shown-once issuance or destructive rotation.
3278
- Provision opens the approval page automatically in interactive terminals;
3279
- use --open to force browser launch or --no-open to suppress it.
3312
+ Provision opens the approval page in your browser automatically whenever the
3313
+ machine can show one, including agent-driven runs; only CI, SSH, and
3314
+ display-less hosts skip it. Use --open to force or --no-open to suppress.
3280
3315
  A fresh device handshake requires --email <odla-account> or ODLA_USER_EMAIL.
3281
3316
  The email is a non-secret identity hint: never provide a password or session
3282
3317
  token. The matching account must already exist, be signed in, explicitly
@@ -3982,4 +4017,4 @@ export {
3982
4017
  smoke,
3983
4018
  runCli
3984
4019
  };
3985
- //# sourceMappingURL=chunk-MWVKOIGR.js.map
4020
+ //# sourceMappingURL=chunk-DC4MIB4X.js.map