@odla-ai/cli 0.30.0 → 0.30.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/README.md +19 -6
- package/dist/bin.cjs +96 -148
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-PPSXHZJI.js → chunk-7V7WVTDT.js} +71 -123
- package/dist/chunk-7V7WVTDT.js.map +1 -0
- package/dist/{cli-CKBUVTJM.js → cli-SZUWA6EF.js} +2 -2
- package/dist/index.cjs +84 -136
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -7
- package/dist/index.d.ts +8 -7
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/skills/odla/SKILL.md +6 -4
- package/dist/chunk-PPSXHZJI.js.map +0 -1
- /package/dist/{cli-CKBUVTJM.js.map → cli-SZUWA6EF.js.map} +0 -0
package/dist/bin.js
CHANGED
|
@@ -174,7 +174,7 @@ function absoluteEntryPath(entryPath) {
|
|
|
174
174
|
|
|
175
175
|
// src/bin.ts
|
|
176
176
|
var argv = process.argv.slice(2);
|
|
177
|
-
requireCurrentCliForProvision(argv).then(() => requireCoherentProvisionRuntime(argv)).then(async () => (await import("./cli-
|
|
177
|
+
requireCurrentCliForProvision(argv).then(() => requireCoherentProvisionRuntime(argv)).then(async () => (await import("./cli-SZUWA6EF.js")).runCli()).catch((err) => {
|
|
178
178
|
console.error(redactSecrets(`odla-ai: ${err instanceof Error ? err.message : String(err)}`));
|
|
179
179
|
process.exitCode = exitCodeFor(err);
|
|
180
180
|
});
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
import process8 from "process";
|
|
14
14
|
|
|
15
15
|
// src/token.ts
|
|
16
|
-
import {
|
|
16
|
+
import { OdlaError, requestToken } from "@odla-ai/db";
|
|
17
17
|
import { createHash } from "crypto";
|
|
18
18
|
import process5 from "process";
|
|
19
19
|
|
|
@@ -117,12 +117,40 @@ function handshakeUrl(platformUrl, userCode) {
|
|
|
117
117
|
|
|
118
118
|
// src/handshake-state.ts
|
|
119
119
|
import { rmSync } from "fs";
|
|
120
|
-
import { dirname
|
|
120
|
+
import { dirname, join } from "path";
|
|
121
121
|
import process4 from "process";
|
|
122
|
+
function handshakeFile(cfg) {
|
|
123
|
+
return join(dirname(cfg.local.tokenFile), "handshake.local.json");
|
|
124
|
+
}
|
|
125
|
+
function clearPendingHandshake(path) {
|
|
126
|
+
rmSync(path, { force: true });
|
|
127
|
+
}
|
|
128
|
+
function minutesLeft(expiresAt) {
|
|
129
|
+
return Math.max(1, Math.round((expiresAt - Date.now()) / 6e4));
|
|
130
|
+
}
|
|
131
|
+
function approvalHint(pending) {
|
|
132
|
+
return `approve code ${pending.userCode} at ${pending.approvalUrl} (${minutesLeft(pending.expiresAt)}m left)`;
|
|
133
|
+
}
|
|
134
|
+
function approvalReminder(out, pending, periodMs = 3e4) {
|
|
135
|
+
const timer = setInterval(() => {
|
|
136
|
+
for (const line of reminderLines({
|
|
137
|
+
userCode: pending.userCode,
|
|
138
|
+
approvalUrl: pending.approvalUrl,
|
|
139
|
+
minutesLeft: minutesLeft(pending.expiresAt)
|
|
140
|
+
}))
|
|
141
|
+
out.log(line);
|
|
142
|
+
}, periodMs);
|
|
143
|
+
timer.unref?.();
|
|
144
|
+
return () => clearInterval(timer);
|
|
145
|
+
}
|
|
146
|
+
function handshakeWaitMs(waitSeconds, interactive = process4.stdout.isTTY === true) {
|
|
147
|
+
if (waitSeconds !== void 0) return waitSeconds * 1e3;
|
|
148
|
+
return interactive ? void 0 : 9e4;
|
|
149
|
+
}
|
|
122
150
|
|
|
123
151
|
// src/local.ts
|
|
124
152
|
import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "fs";
|
|
125
|
-
import { dirname, isAbsolute, relative, resolve } from "path";
|
|
153
|
+
import { dirname as dirname2, isAbsolute, relative, resolve } from "path";
|
|
126
154
|
var GITIGNORE_LINES = [".odla/*.local.json", ".odla/dev-token.json", ".dev.vars"];
|
|
127
155
|
function readJsonFile(path) {
|
|
128
156
|
try {
|
|
@@ -190,7 +218,7 @@ function o11yDevVars(cfg) {
|
|
|
190
218
|
function resolveWriteDevVarsTarget(cfg, requested) {
|
|
191
219
|
if (!requested) return null;
|
|
192
220
|
if (requested === true) return cfg.local.devVarsFile;
|
|
193
|
-
return resolve(
|
|
221
|
+
return resolve(dirname2(cfg.configPath), requested);
|
|
194
222
|
}
|
|
195
223
|
function writeDevVars(path, credentials, env, o11y) {
|
|
196
224
|
const entry = credentials.envs[env];
|
|
@@ -230,7 +258,7 @@ function isManagedDevVar(line) {
|
|
|
230
258
|
return !!match?.[1] && MANAGED_DEV_VARS.has(match[1]);
|
|
231
259
|
}
|
|
232
260
|
function writePrivateText(path, text2) {
|
|
233
|
-
mkdirSync(
|
|
261
|
+
mkdirSync(dirname2(path), { recursive: true });
|
|
234
262
|
const temporary = `${path}.tmp-${process.pid}-${Date.now()}`;
|
|
235
263
|
writeFileSync(temporary, text2, { mode: 384 });
|
|
236
264
|
chmodSync(temporary, 384);
|
|
@@ -246,58 +274,6 @@ function displayPath(path, rootDir = process.cwd()) {
|
|
|
246
274
|
return rel && !rel.startsWith("..") ? rel : path;
|
|
247
275
|
}
|
|
248
276
|
|
|
249
|
-
// src/handshake-state.ts
|
|
250
|
-
function handshakeFile(cfg) {
|
|
251
|
-
return join(dirname2(cfg.local.tokenFile), "handshake.local.json");
|
|
252
|
-
}
|
|
253
|
-
var RESUME_MARGIN_MS = 5e3;
|
|
254
|
-
function readPendingHandshake(path, platform, email, requiredGrant) {
|
|
255
|
-
const pending = readJsonFile(path);
|
|
256
|
-
if (!pending || pending.platform !== platform || pending.email !== email) return null;
|
|
257
|
-
if (typeof pending.userCode !== "string" || typeof pending.deviceCode !== "string") return null;
|
|
258
|
-
if (typeof pending.expiresAt !== "number" || pending.expiresAt <= Date.now() + RESUME_MARGIN_MS) return null;
|
|
259
|
-
if (requiredGrant && !grantCovers(pending, requiredGrant)) return null;
|
|
260
|
-
return {
|
|
261
|
-
interval: typeof pending.interval === "number" ? pending.interval : 3,
|
|
262
|
-
...pending,
|
|
263
|
-
approvalUrl: handshakeUrl(platform, pending.userCode)
|
|
264
|
-
};
|
|
265
|
-
}
|
|
266
|
-
function grantCovers(stored, required) {
|
|
267
|
-
if (required.optionalProjectCapabilities.length === 0) return true;
|
|
268
|
-
return required.projectIds.every((id) => stored.projectIds?.includes(id)) && required.optionalProjectCapabilities.every(
|
|
269
|
-
(capability) => stored.optionalProjectCapabilities?.includes(capability)
|
|
270
|
-
);
|
|
271
|
-
}
|
|
272
|
-
function writePendingHandshake(path, pending) {
|
|
273
|
-
writePrivateJson(path, pending);
|
|
274
|
-
}
|
|
275
|
-
function clearPendingHandshake(path) {
|
|
276
|
-
rmSync(path, { force: true });
|
|
277
|
-
}
|
|
278
|
-
function minutesLeft(expiresAt) {
|
|
279
|
-
return Math.max(1, Math.round((expiresAt - Date.now()) / 6e4));
|
|
280
|
-
}
|
|
281
|
-
function approvalHint(pending) {
|
|
282
|
-
return `approve code ${pending.userCode} at ${pending.approvalUrl} (${minutesLeft(pending.expiresAt)}m left)`;
|
|
283
|
-
}
|
|
284
|
-
function approvalReminder(out, pending, periodMs = 3e4) {
|
|
285
|
-
const timer = setInterval(() => {
|
|
286
|
-
for (const line of reminderLines({
|
|
287
|
-
userCode: pending.userCode,
|
|
288
|
-
approvalUrl: pending.approvalUrl,
|
|
289
|
-
minutesLeft: minutesLeft(pending.expiresAt)
|
|
290
|
-
}))
|
|
291
|
-
out.log(line);
|
|
292
|
-
}, periodMs);
|
|
293
|
-
timer.unref?.();
|
|
294
|
-
return () => clearInterval(timer);
|
|
295
|
-
}
|
|
296
|
-
function handshakeWaitMs(waitSeconds, interactive = process4.stdout.isTTY === true) {
|
|
297
|
-
if (waitSeconds !== void 0) return waitSeconds * 1e3;
|
|
298
|
-
return interactive ? void 0 : 9e4;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
277
|
// src/token.ts
|
|
302
278
|
async function getDeveloperToken(cfg, options, doFetch, out, grantRequest = {}) {
|
|
303
279
|
const audience = platformAudience(cfg.platformUrl);
|
|
@@ -336,8 +312,8 @@ async function getDeveloperToken(cfg, options, doFetch, out, grantRequest = {})
|
|
|
336
312
|
grantIntent
|
|
337
313
|
};
|
|
338
314
|
const waitMs = handshakeWaitMs(options.wait);
|
|
339
|
-
|
|
340
|
-
const { token, expiresAt } = await
|
|
315
|
+
clearPendingHandshake(ctx.pendingFile);
|
|
316
|
+
const { token, expiresAt } = await freshHandshake(ctx, waitMs);
|
|
341
317
|
clearPendingHandshake(ctx.pendingFile);
|
|
342
318
|
writePrivateJson(cfg.local.tokenFile, {
|
|
343
319
|
platform: audience,
|
|
@@ -350,47 +326,6 @@ async function getDeveloperToken(cfg, options, doFetch, out, grantRequest = {})
|
|
|
350
326
|
out.error(`auth: developer token cached (${displayPath(cfg.local.tokenFile, cfg.rootDir)})`);
|
|
351
327
|
return token;
|
|
352
328
|
}
|
|
353
|
-
async function resumePendingHandshake(ctx, waitMs) {
|
|
354
|
-
const pending = readPendingHandshake(
|
|
355
|
-
ctx.pendingFile,
|
|
356
|
-
ctx.audience,
|
|
357
|
-
ctx.email,
|
|
358
|
-
ctx.grantIntent
|
|
359
|
-
);
|
|
360
|
-
if (!pending) return null;
|
|
361
|
-
ctx.out.error("");
|
|
362
|
-
ctx.out.error(`auth: resuming pending handshake \u2014 ${approvalHint(pending)}`);
|
|
363
|
-
await presentHandshakeApproval(ctx.out, {
|
|
364
|
-
userCode: pending.userCode,
|
|
365
|
-
approvalUrl: pending.approvalUrl,
|
|
366
|
-
minutesLeft: Math.max(1, Math.floor((pending.expiresAt - Date.now()) / 6e4)),
|
|
367
|
-
purpose: `sign this terminal in as ${ctx.email}`
|
|
368
|
-
}, ctx.options);
|
|
369
|
-
ctx.out.error("");
|
|
370
|
-
const stopReminder = approvalReminder(ctx.out, pending);
|
|
371
|
-
try {
|
|
372
|
-
return await collectToken({
|
|
373
|
-
endpoint: ctx.cfg.platformUrl,
|
|
374
|
-
deviceCode: pending.deviceCode,
|
|
375
|
-
expiresAt: pending.expiresAt,
|
|
376
|
-
interval: pending.interval,
|
|
377
|
-
waitMs,
|
|
378
|
-
fetch: ctx.doFetch
|
|
379
|
-
});
|
|
380
|
-
} catch (err) {
|
|
381
|
-
const code = err instanceof OdlaError ? err.code : void 0;
|
|
382
|
-
if (code === "handshake_pending") throw stillPending(pending, ctx.email);
|
|
383
|
-
if (code === "handshake_expired" || code === "handshake_timeout") {
|
|
384
|
-
clearPendingHandshake(ctx.pendingFile);
|
|
385
|
-
ctx.out.error("auth: pending handshake lapsed unapproved; starting a fresh one");
|
|
386
|
-
return null;
|
|
387
|
-
}
|
|
388
|
-
if (code === "handshake_denied") clearPendingHandshake(ctx.pendingFile);
|
|
389
|
-
throw err;
|
|
390
|
-
} finally {
|
|
391
|
-
stopReminder();
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
329
|
async function freshHandshake(ctx, waitMs) {
|
|
395
330
|
let started;
|
|
396
331
|
let stopReminder;
|
|
@@ -418,7 +353,6 @@ async function freshHandshake(ctx, waitMs) {
|
|
|
418
353
|
projectIds: ctx.grantIntent.projectIds,
|
|
419
354
|
optionalProjectCapabilities: ctx.grantIntent.optionalProjectCapabilities
|
|
420
355
|
};
|
|
421
|
-
writePendingHandshake(ctx.pendingFile, started);
|
|
422
356
|
await presentHandshakeApproval(ctx.out, {
|
|
423
357
|
userCode,
|
|
424
358
|
approvalUrl,
|
|
@@ -454,7 +388,7 @@ function projectAgentHandle(appId) {
|
|
|
454
388
|
function stillPending(pending, email) {
|
|
455
389
|
return new OdlaError(
|
|
456
390
|
"handshake_pending",
|
|
457
|
-
`handshake still pending \u2014 ask ${email} to ${approvalHint(pending)}
|
|
391
|
+
`handshake still pending \u2014 ask ${email} to ${approvalHint(pending)}; if this command exits, re-run it to request a new code`,
|
|
458
392
|
{ retryable: true }
|
|
459
393
|
);
|
|
460
394
|
}
|
|
@@ -4781,28 +4715,31 @@ async function smoke(options) {
|
|
|
4781
4715
|
const out = options.stdout ?? console;
|
|
4782
4716
|
const cfg = await loadProjectConfig(options.configPath);
|
|
4783
4717
|
const env = resolveEnv(cfg, options.env);
|
|
4784
|
-
const
|
|
4785
|
-
|
|
4718
|
+
const runtime = options.runtime === true;
|
|
4719
|
+
const credentials = runtime ? null : readCredentials(cfg.local.credentialsFile);
|
|
4720
|
+
if (!runtime && !credentials) {
|
|
4786
4721
|
throw new Error(`local credentials missing: ${displayPath(cfg.local.credentialsFile, cfg.rootDir)}. Run "odla-ai provision --write-dev-vars".`);
|
|
4787
4722
|
}
|
|
4788
|
-
if (credentials.appId !== cfg.app.id) {
|
|
4723
|
+
if (credentials && credentials.appId !== cfg.app.id) {
|
|
4789
4724
|
throw new Error(`local credentials are for app "${credentials.appId}", but config app is "${cfg.app.id}"`);
|
|
4790
4725
|
}
|
|
4791
|
-
const entry = credentials
|
|
4792
|
-
if (!entry?.tenantId) {
|
|
4726
|
+
const entry = credentials?.envs[env];
|
|
4727
|
+
if (!runtime && !entry?.tenantId) {
|
|
4793
4728
|
throw new Error(`local credentials have no tenant for env "${env}". Run "odla-ai provision --write-dev-vars".`);
|
|
4794
4729
|
}
|
|
4795
4730
|
const hasDb = cfg.services.includes("db");
|
|
4796
4731
|
const hasO11y = cfg.services.includes("o11y");
|
|
4797
|
-
if (hasDb && !entry
|
|
4732
|
+
if (!runtime && hasDb && !entry?.dbKey) {
|
|
4798
4733
|
throw new Error(`local credentials have no db key for env "${env}". Run "odla-ai provision --write-dev-vars".`);
|
|
4799
4734
|
}
|
|
4800
|
-
if (hasO11y && !entry
|
|
4735
|
+
if (!runtime && hasO11y && !entry?.o11yToken) {
|
|
4801
4736
|
throw new Error(`local credentials have no o11y token for env "${env}". Run "odla-ai provision --write-dev-vars".`);
|
|
4802
4737
|
}
|
|
4803
4738
|
const doFetch = options.fetch ?? fetch;
|
|
4739
|
+
const tenantId = entry?.tenantId ?? resolveTenant(cfg, env).tenant;
|
|
4804
4740
|
out.log(`smoke: ${cfg.app.id}/${env}`);
|
|
4805
|
-
out.log(`
|
|
4741
|
+
out.log(` mode: ${runtime ? "runtime (Worker-held credentials)" : "local credentials"}`);
|
|
4742
|
+
out.log(` tenant: ${tenantId}`);
|
|
4806
4743
|
const publicConfig = await getJson(doFetch, publicConfigUrl(cfg.platformUrl, cfg.app.id, env), void 0);
|
|
4807
4744
|
out.log(` public-config: ok`);
|
|
4808
4745
|
if (cfg.services.includes("ai") && cfg.ai?.provider) {
|
|
@@ -4816,7 +4753,7 @@ async function smoke(options) {
|
|
|
4816
4753
|
if (mode !== "hosted") throw new Error(`ai mode mismatch: expected "hosted", public-config has "${String(mode ?? "none")}"`);
|
|
4817
4754
|
out.log(" ai: hosted");
|
|
4818
4755
|
}
|
|
4819
|
-
if (hasO11y) out.log(` o11y: credentials present`);
|
|
4756
|
+
if (hasO11y) out.log(runtime ? ` o11y: Worker-held credential` : ` o11y: credentials present`);
|
|
4820
4757
|
if (cfg.services.includes("calendar")) {
|
|
4821
4758
|
const token = await getDeveloperToken(
|
|
4822
4759
|
cfg,
|
|
@@ -4835,10 +4772,10 @@ async function smoke(options) {
|
|
|
4835
4772
|
out.log(` calendar: ${status.status}, bookable (booking \u2192 ${status.bookingCalendarId ?? "primary"})`);
|
|
4836
4773
|
}
|
|
4837
4774
|
const database = await resolveDatabaseConfig(cfg);
|
|
4838
|
-
if (hasDb) {
|
|
4775
|
+
if (hasDb && !runtime) {
|
|
4839
4776
|
const expectedSchema = database.schema;
|
|
4840
4777
|
const expectedEntities = serializedEntities(expectedSchema);
|
|
4841
|
-
const liveSchemaPayload = await getJson(doFetch, `${cfg.dbEndpoint}/app/${encodeURIComponent(
|
|
4778
|
+
const liveSchemaPayload = await getJson(doFetch, `${cfg.dbEndpoint}/app/${encodeURIComponent(tenantId)}/schema`, entry.dbKey);
|
|
4842
4779
|
const liveSchema = liveSchemaPayload.schema ?? liveSchemaPayload;
|
|
4843
4780
|
const liveEntities = serializedEntities(liveSchema);
|
|
4844
4781
|
if (expectedEntities.length) {
|
|
@@ -4848,7 +4785,7 @@ async function smoke(options) {
|
|
|
4848
4785
|
out.log(` schema: ${liveEntities.length} entities`);
|
|
4849
4786
|
const aggregateEntity = expectedEntities[0] ?? liveEntities[0];
|
|
4850
4787
|
if (aggregateEntity) {
|
|
4851
|
-
const aggregate = await postJson2(doFetch, `${cfg.dbEndpoint}/app/${encodeURIComponent(
|
|
4788
|
+
const aggregate = await postJson2(doFetch, `${cfg.dbEndpoint}/app/${encodeURIComponent(tenantId)}/aggregate`, entry.dbKey, {
|
|
4852
4789
|
ns: aggregateEntity,
|
|
4853
4790
|
aggregate: { count: true }
|
|
4854
4791
|
});
|
|
@@ -4857,9 +4794,20 @@ async function smoke(options) {
|
|
|
4857
4794
|
} else {
|
|
4858
4795
|
out.log(` aggregate: skipped (schema has no entities)`);
|
|
4859
4796
|
}
|
|
4797
|
+
} else if (hasDb) {
|
|
4798
|
+
out.log(` db: Worker-held credential (direct schema/aggregate skipped)`);
|
|
4860
4799
|
} else {
|
|
4861
4800
|
out.log(` db: skipped (not enabled)`);
|
|
4862
4801
|
}
|
|
4802
|
+
if (runtime) {
|
|
4803
|
+
const link = cfg.links?.[env];
|
|
4804
|
+
if (!link) throw new Error(`runtime smoke requires links.${env} in odla.config.mjs`);
|
|
4805
|
+
const res = await doFetch(link, { redirect: "manual" });
|
|
4806
|
+
if (res.status < 200 || res.status >= 500) {
|
|
4807
|
+
throw new Error(`runtime target ${new URL(link).origin} returned ${res.status}`);
|
|
4808
|
+
}
|
|
4809
|
+
out.log(` runtime target: ${res.status}`);
|
|
4810
|
+
}
|
|
4863
4811
|
const probes = database.integrations.flatMap(
|
|
4864
4812
|
(integration) => (integration.probes ?? []).map((probe) => ({ integration: integration.id, probe }))
|
|
4865
4813
|
);
|
|
@@ -5062,10 +5010,11 @@ async function projectCommand(command, parsed, deps) {
|
|
|
5062
5010
|
return true;
|
|
5063
5011
|
}
|
|
5064
5012
|
if (command === "smoke") {
|
|
5065
|
-
assertArgs(parsed, ["config", "env", "token", "email", "open"], 1);
|
|
5013
|
+
assertArgs(parsed, ["config", "env", "runtime", "token", "email", "open"], 1);
|
|
5066
5014
|
await smoke({
|
|
5067
5015
|
configPath: stringOpt(parsed.options.config) ?? "odla.config.mjs",
|
|
5068
5016
|
env: stringOpt(parsed.options.env),
|
|
5017
|
+
runtime: parsed.options.runtime === true,
|
|
5069
5018
|
token: stringOpt(parsed.options.token),
|
|
5070
5019
|
email: stringOpt(parsed.options.email),
|
|
5071
5020
|
open: parsed.options.open === false ? false : parsed.options.open === true ? true : void 0,
|
|
@@ -8908,7 +8857,7 @@ Usage:
|
|
|
8908
8857
|
odla-ai provision [--live] [--config odla.config.mjs] [--email <odla-account>] [--request-grant] [--wait <seconds>] [--dry-run] [--push-secrets] [--rotate-o11y-token] [--write-dev-vars[=path]] [--yes]
|
|
8909
8858
|
odla-ai credentials list [--config odla.config.mjs] [--env dev] [--all] [--json]
|
|
8910
8859
|
odla-ai credentials revoke <receipt-id> [--config odla.config.mjs] [--json]
|
|
8911
|
-
odla-ai smoke [--config odla.config.mjs] [--env dev] [--email <odla-account>] [--no-open]
|
|
8860
|
+
odla-ai smoke [--config odla.config.mjs] [--env dev] [--runtime] [--email <odla-account>] [--no-open]
|
|
8912
8861
|
odla-ai skill install [--dir <project>] [--agent <name>] [--global] [--force]
|
|
8913
8862
|
odla-ai secrets push --env <env> [--config odla.config.mjs] [--dry-run] [--yes]
|
|
8914
8863
|
odla-ai secrets set <name> --env <env> (--from-env <NAME>|--stdin) [--email <odla-account>] [--config odla.config.mjs] [--yes]
|
|
@@ -9010,7 +8959,7 @@ Commands:
|
|
|
9010
8959
|
"provision --live --yes" initializes only the live instance of
|
|
9011
8960
|
an existing sandbox app and enables every configured service;
|
|
9012
8961
|
no edit to the dev-first envs list is required.
|
|
9013
|
-
smoke Verify
|
|
8962
|
+
smoke Verify local service access, or use --runtime for a Worker-held credential deployment.
|
|
9014
8963
|
skill Same installer; --agent accepts all, claude, codex, cursor,
|
|
9015
8964
|
copilot, gemini, or agents (repeatable or comma-separated).
|
|
9016
8965
|
secrets Push configured db/o11y secrets into the Worker via wrangler
|
|
@@ -9050,12 +8999,11 @@ Safety:
|
|
|
9050
8999
|
attempts to open it \u2014 including in CI, SSH, display-less, and agent-driven
|
|
9051
9000
|
shells. Only --no-open suppresses the attempt. Browser launch is best-effort:
|
|
9052
9001
|
agents with browser control must open that exact URL immediately; otherwise
|
|
9053
|
-
they must give it to the human verbatim. A
|
|
9054
|
-
|
|
9055
|
-
the same code. Outside an interactive terminal the wait is capped (90s by
|
|
9002
|
+
they must give it to the human verbatim. A device code remains only in the
|
|
9003
|
+
running process. Outside an interactive terminal the wait is capped (90s by
|
|
9056
9004
|
default, --wait <seconds> to change); a still-pending handshake then exits
|
|
9057
|
-
with code 75
|
|
9058
|
-
|
|
9005
|
+
with code 75. Rerunning always requests and opens a new code; older clients'
|
|
9006
|
+
persisted pending state is discarded.
|
|
9059
9007
|
A fresh device handshake requires --email <odla-account> or ODLA_USER_EMAIL.
|
|
9060
9008
|
The email is a non-secret identity hint: never provide a password or session
|
|
9061
9009
|
token. It is the email shown by the signed-in odla account \u2014 never infer it
|
|
@@ -13246,4 +13194,4 @@ export {
|
|
|
13246
13194
|
isTerminalHostedSecurityStatus,
|
|
13247
13195
|
runCli
|
|
13248
13196
|
};
|
|
13249
|
-
//# sourceMappingURL=chunk-
|
|
13197
|
+
//# sourceMappingURL=chunk-7V7WVTDT.js.map
|