@odla-ai/cli 0.10.0 → 0.10.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 +33 -6
- package/REQUIREMENTS.md +17 -1
- package/dist/bin.cjs +61 -31
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-WDKBW4BE.js → chunk-MWVKOIGR.js} +62 -32
- package/dist/chunk-MWVKOIGR.js.map +1 -0
- package/dist/index.cjs +61 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +30 -8
- package/dist/index.d.ts +30 -8
- package/dist/index.js +1 -1
- package/llms.txt +64 -15
- package/package.json +2 -2
- package/skills/odla/SKILL.md +7 -2
- package/skills/odla/references/build.md +5 -3
- package/skills/odla-migrate/SKILL.md +3 -0
- package/skills/odla-migrate/references/phase-2-db.md +8 -6
- package/skills/odla-migrate/references/secrets-map.md +2 -1
- package/skills/odla-migrate/references/troubleshooting.md +3 -1
- package/skills/odla-o11y-debug/SKILL.md +7 -3
- package/dist/chunk-WDKBW4BE.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -252,14 +252,16 @@ async function getDeveloperToken(cfg, options, doFetch, out) {
|
|
|
252
252
|
return cached.token;
|
|
253
253
|
}
|
|
254
254
|
const browser = approvalBrowser(options);
|
|
255
|
+
const email = handshakeEmail(options.email, cached?.platform === audience ? cached.email : void 0);
|
|
255
256
|
const { token, expiresAt } = await (0, import_db.requestToken)({
|
|
256
257
|
endpoint: cfg.platformUrl,
|
|
258
|
+
email,
|
|
257
259
|
label: `${cfg.app.id} provisioner`,
|
|
258
260
|
fetch: doFetch,
|
|
259
|
-
onCode: async ({ userCode, expiresIn }) => {
|
|
260
|
-
const approvalUrl = handshakeUrl(cfg.platformUrl, userCode);
|
|
261
|
+
onCode: async ({ userCode, expiresIn, verificationUriComplete }) => {
|
|
262
|
+
const approvalUrl = verificationUriComplete ?? handshakeUrl(cfg.platformUrl, userCode);
|
|
261
263
|
out.log("");
|
|
262
|
-
out.log(`
|
|
264
|
+
out.log(`Review, then approve code ${userCode} at ${approvalUrl} within ${Math.floor(expiresIn / 60)}m.`);
|
|
263
265
|
if (browser.open) {
|
|
264
266
|
try {
|
|
265
267
|
await (options.openApprovalUrl ?? openUrl)(approvalUrl);
|
|
@@ -273,10 +275,17 @@ async function getDeveloperToken(cfg, options, doFetch, out) {
|
|
|
273
275
|
out.log("");
|
|
274
276
|
}
|
|
275
277
|
});
|
|
276
|
-
writePrivateJson(cfg.local.tokenFile, { platform: audience, token, expiresAt });
|
|
278
|
+
writePrivateJson(cfg.local.tokenFile, { platform: audience, email, token, expiresAt });
|
|
277
279
|
out.log(`auth: developer token cached (${displayPath(cfg.local.tokenFile, cfg.rootDir)})`);
|
|
278
280
|
return token;
|
|
279
281
|
}
|
|
282
|
+
function handshakeEmail(value, cached) {
|
|
283
|
+
const email = (value ?? import_node_process2.default.env.ODLA_USER_EMAIL ?? cached ?? "").trim().toLowerCase();
|
|
284
|
+
if (email.length > 254 || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
|
|
285
|
+
throw new Error("a fresh odla handshake requires --email <account> or ODLA_USER_EMAIL");
|
|
286
|
+
}
|
|
287
|
+
return email;
|
|
288
|
+
}
|
|
280
289
|
function approvalBrowser(options) {
|
|
281
290
|
if (options.open === true) return { open: true, mode: "forced" };
|
|
282
291
|
if (options.open === false) return { open: false, reason: "disabled by --no-open" };
|
|
@@ -369,14 +378,16 @@ async function scopedToken(platform, scope, options, doFetch, out) {
|
|
|
369
378
|
out.log(`auth: using cached ${scope} grant (${tokenFile})`);
|
|
370
379
|
return cached.token;
|
|
371
380
|
}
|
|
381
|
+
const email = handshakeEmail(options.email, cache?.platform === audience ? cache.email : void 0);
|
|
372
382
|
const { token, expiresAt } = await (0, import_db2.requestToken)({
|
|
373
383
|
endpoint: audience,
|
|
384
|
+
email,
|
|
374
385
|
label: `odla CLI admin AI (${scope})`,
|
|
375
386
|
scopes: [scope],
|
|
376
387
|
fetch: doFetch,
|
|
377
|
-
onCode: async ({ userCode, expiresIn }) => {
|
|
378
|
-
const approvalUrl = handshakeUrl(audience, userCode);
|
|
379
|
-
out.log(`
|
|
388
|
+
onCode: async ({ userCode, expiresIn, verificationUriComplete }) => {
|
|
389
|
+
const approvalUrl = verificationUriComplete ?? handshakeUrl(audience, userCode);
|
|
390
|
+
out.log(`Review, then approve scoped request ${userCode} at ${approvalUrl} within ${Math.floor(expiresIn / 60)}m.`);
|
|
380
391
|
const shouldOpen = options.open === true || options.open !== false && !import_node_process4.default.env.CI && Boolean(import_node_process4.default.stdin.isTTY && import_node_process4.default.stdout.isTTY);
|
|
381
392
|
if (shouldOpen) await (options.openApprovalUrl ?? openUrl)(approvalUrl).catch(() => void 0);
|
|
382
393
|
}
|
|
@@ -384,7 +395,7 @@ async function scopedToken(platform, scope, options, doFetch, out) {
|
|
|
384
395
|
const tokens = cache?.platform === audience ? { ...cache.tokens ?? {} } : {};
|
|
385
396
|
tokens[scope] = { token, expiresAt };
|
|
386
397
|
if ((0, import_node_fs2.existsSync)(`${import_node_process4.default.cwd()}/.git`)) ensureGitignore(import_node_process4.default.cwd(), [tokenFile]);
|
|
387
|
-
writePrivateJson(tokenFile, { platform: audience, tokens });
|
|
398
|
+
writePrivateJson(tokenFile, { platform: audience, email, tokens });
|
|
388
399
|
out.log(`auth: cached ${scope} grant (${tokenFile}; mode 0600)`);
|
|
389
400
|
return token;
|
|
390
401
|
}
|
|
@@ -554,6 +565,7 @@ async function adminAi(options) {
|
|
|
554
565
|
platform,
|
|
555
566
|
scope,
|
|
556
567
|
token: options.token,
|
|
568
|
+
email: options.email,
|
|
557
569
|
open: options.open,
|
|
558
570
|
fetch: doFetch,
|
|
559
571
|
stdout: out,
|
|
@@ -813,6 +825,7 @@ async function adminCommand(parsed) {
|
|
|
813
825
|
"platform",
|
|
814
826
|
"json",
|
|
815
827
|
"open",
|
|
828
|
+
"email",
|
|
816
829
|
"provider",
|
|
817
830
|
"model",
|
|
818
831
|
"enabled",
|
|
@@ -840,6 +853,7 @@ async function adminCommand(parsed) {
|
|
|
840
853
|
maxOutputTokens: numberOpt(parsed.options["max-output-tokens"], "--max-output-tokens"),
|
|
841
854
|
maxCallsPerRun: numberOpt(parsed.options["max-calls-per-run"], "--max-calls-per-run"),
|
|
842
855
|
platform: stringOpt(parsed.options.platform),
|
|
856
|
+
email: stringOpt(parsed.options.email),
|
|
843
857
|
json: parsed.options.json === true,
|
|
844
858
|
open: parsed.options.open === false ? false : parsed.options.open === true ? true : void 0,
|
|
845
859
|
credentialProvider: credentialSet ? parsed.positionals[4] : void 0,
|
|
@@ -859,6 +873,7 @@ async function adminCommand(parsed) {
|
|
|
859
873
|
// src/capabilities.ts
|
|
860
874
|
var CAPABILITIES = {
|
|
861
875
|
cli: [
|
|
876
|
+
"start an email-bound device request without accepting a password or user session token",
|
|
862
877
|
"register the app and enable configured services per environment",
|
|
863
878
|
"issue, persist, and explicitly rotate configured service credentials",
|
|
864
879
|
"write local Worker values and push deployed Worker secrets through Wrangler stdin",
|
|
@@ -877,7 +892,7 @@ var CAPABILITIES = {
|
|
|
877
892
|
"wire @odla-ai/calendar into trusted Worker code and keep the app admin key out of browsers"
|
|
878
893
|
],
|
|
879
894
|
human: [
|
|
880
|
-
"
|
|
895
|
+
"provide the existing odla account email, then sign in and explicitly review/approve the exact device code",
|
|
881
896
|
"review mirrored calendar/attendee disclosure and complete the server-issued Google consent flow",
|
|
882
897
|
"consent to production changes with --yes",
|
|
883
898
|
"request destructive credential rotation explicitly",
|
|
@@ -887,6 +902,7 @@ var CAPABILITIES = {
|
|
|
887
902
|
],
|
|
888
903
|
studio: [
|
|
889
904
|
"view telemetry and environment state",
|
|
905
|
+
"let signed-in users inventory/revoke their own agent grants and admins audit/global-revoke them",
|
|
890
906
|
"review calendar connection, granted read scope, selected calendars, and sync health without exposing provider tokens",
|
|
891
907
|
"perform manual credential recovery when the CLI's local shown-once copy is unavailable",
|
|
892
908
|
"configure system AI purposes and view app/environment/run-attributed usage",
|
|
@@ -1420,6 +1436,7 @@ async function lifecycleContext(options) {
|
|
|
1420
1436
|
{
|
|
1421
1437
|
configPath: cfg.configPath,
|
|
1422
1438
|
token: options.token,
|
|
1439
|
+
email: options.email,
|
|
1423
1440
|
open: options.open,
|
|
1424
1441
|
interactive: options.interactive,
|
|
1425
1442
|
openApprovalUrl: options.openConsentUrl
|
|
@@ -1836,13 +1853,13 @@ Usage:
|
|
|
1836
1853
|
odla-ai setup [--dir <project>] [--agent <name>] [--global] [--force]
|
|
1837
1854
|
odla-ai init --app-id <id> --name <name> [--services db,ai,o11y,calendar] [--env dev --env prod]
|
|
1838
1855
|
odla-ai doctor [--config odla.config.mjs]
|
|
1839
|
-
odla-ai calendar status [--env dev] [--json]
|
|
1840
|
-
odla-ai calendar calendars [--env dev] [--json]
|
|
1841
|
-
odla-ai calendar connect [--env dev] [--no-open] [--yes]
|
|
1842
|
-
odla-ai calendar resync [--env dev] [--yes]
|
|
1843
|
-
odla-ai calendar disconnect [--env dev] --yes
|
|
1856
|
+
odla-ai calendar status [--env dev] [--email <odla-account>] [--json]
|
|
1857
|
+
odla-ai calendar calendars [--env dev] [--email <odla-account>] [--json]
|
|
1858
|
+
odla-ai calendar connect [--env dev] [--email <odla-account>] [--no-open] [--yes]
|
|
1859
|
+
odla-ai calendar resync [--env dev] [--email <odla-account>] [--yes]
|
|
1860
|
+
odla-ai calendar disconnect [--env dev] [--email <odla-account>] --yes
|
|
1844
1861
|
odla-ai capabilities [--json]
|
|
1845
|
-
odla-ai admin ai show [--platform https://odla.ai] [--json]
|
|
1862
|
+
odla-ai admin ai show [--platform https://odla.ai] [--email <odla-account>] [--json]
|
|
1846
1863
|
odla-ai admin ai models [--provider <id>] [--json]
|
|
1847
1864
|
odla-ai admin ai set <purpose> [--provider <id>] [--model <id>] [--enabled|--no-enabled]
|
|
1848
1865
|
odla-ai admin ai set security --discovery-provider <id> --discovery-model <id>
|
|
@@ -1851,7 +1868,7 @@ Usage:
|
|
|
1851
1868
|
odla-ai admin ai credential set <provider> (--from-env <NAME>|--stdin)
|
|
1852
1869
|
odla-ai admin ai usage [--app-id <id>] [--env <env>] [--run-id <id>] [--limit <1-500>] [--json]
|
|
1853
1870
|
odla-ai admin ai audit [--limit <1-200>] [--json]
|
|
1854
|
-
odla-ai security github connect [--repo owner/name] [--env dev] [--no-open]
|
|
1871
|
+
odla-ai security github connect [--repo owner/name] [--env dev] [--email <odla-account>] [--no-open]
|
|
1855
1872
|
odla-ai security github disconnect --source <id> [--env dev] [--yes]
|
|
1856
1873
|
odla-ai security plan [--env dev] [--json]
|
|
1857
1874
|
odla-ai security sources [--env dev] [--json]
|
|
@@ -1860,12 +1877,12 @@ Usage:
|
|
|
1860
1877
|
odla-ai security report <job-id> [--json]
|
|
1861
1878
|
odla-ai security run [target] --ack-redacted-source [--env dev] [--profile odla] [--fail-on high]
|
|
1862
1879
|
odla-ai security run [target] --self --ack-redacted-source
|
|
1863
|
-
odla-ai provision [--config odla.config.mjs] [--dry-run] [--push-secrets] [--rotate-o11y-token] [--write-dev-vars[=path]] [--yes]
|
|
1864
|
-
odla-ai smoke [--config odla.config.mjs] [--env dev] [--no-open]
|
|
1880
|
+
odla-ai provision [--config odla.config.mjs] [--email <odla-account>] [--dry-run] [--push-secrets] [--rotate-o11y-token] [--write-dev-vars[=path]] [--yes]
|
|
1881
|
+
odla-ai smoke [--config odla.config.mjs] [--env dev] [--email <odla-account>] [--no-open]
|
|
1865
1882
|
odla-ai skill install [--dir <project>] [--agent <name>] [--global] [--force]
|
|
1866
1883
|
odla-ai secrets push --env <env> [--config odla.config.mjs] [--dry-run] [--yes]
|
|
1867
|
-
odla-ai secrets set <name> --env <env> (--from-env <NAME>|--stdin) [--config odla.config.mjs] [--yes]
|
|
1868
|
-
odla-ai secrets set-clerk-key --env <env> (--from-env <NAME>|--stdin) [--config odla.config.mjs] [--yes]
|
|
1884
|
+
odla-ai secrets set <name> --env <env> (--from-env <NAME>|--stdin) [--email <odla-account>] [--config odla.config.mjs] [--yes]
|
|
1885
|
+
odla-ai secrets set-clerk-key --env <env> (--from-env <NAME>|--stdin) [--email <odla-account>] [--config odla.config.mjs] [--yes]
|
|
1869
1886
|
odla-ai version
|
|
1870
1887
|
|
|
1871
1888
|
Commands:
|
|
@@ -1893,6 +1910,10 @@ Safety:
|
|
|
1893
1910
|
preflights Wrangler before any shown-once issuance or destructive rotation.
|
|
1894
1911
|
Provision opens the approval page automatically in interactive terminals;
|
|
1895
1912
|
use --open to force browser launch or --no-open to suppress it.
|
|
1913
|
+
A fresh device handshake requires --email <odla-account> or ODLA_USER_EMAIL.
|
|
1914
|
+
The email is a non-secret identity hint: never provide a password or session
|
|
1915
|
+
token. The matching account must already exist, be signed in, explicitly
|
|
1916
|
+
review the exact code, and finish any current request before claiming another.
|
|
1896
1917
|
Calendar setup has a second human checkpoint: odla issues a state-bound Google consent URL;
|
|
1897
1918
|
OAuth codes and refresh tokens never enter the CLI, repo, chat, or app.
|
|
1898
1919
|
GitHub security uses source-read-only access plus optional metadata-only Checks write: the CLI never asks
|
|
@@ -2523,7 +2544,7 @@ async function hostedSecurityContext(parsed, dependencies) {
|
|
|
2523
2544
|
const open = parsed.options.open === false ? false : parsed.options.open === true ? true : void 0;
|
|
2524
2545
|
const token = await getDeveloperToken(
|
|
2525
2546
|
cfg,
|
|
2526
|
-
{ configPath, open, openApprovalUrl: dependencies.openUrl },
|
|
2547
|
+
{ configPath, email: stringOpt(parsed.options.email), open, openApprovalUrl: dependencies.openUrl },
|
|
2527
2548
|
doFetch,
|
|
2528
2549
|
stdout
|
|
2529
2550
|
);
|
|
@@ -3152,6 +3173,7 @@ async function runSourceSecurityCommand(parsed, dependencies, sourceId) {
|
|
|
3152
3173
|
"source",
|
|
3153
3174
|
"ref",
|
|
3154
3175
|
"follow",
|
|
3176
|
+
"email",
|
|
3155
3177
|
"open",
|
|
3156
3178
|
"json",
|
|
3157
3179
|
"ack-redacted-source",
|
|
@@ -3240,6 +3262,7 @@ async function runLocalSecurityCommand(parsed, dependencies) {
|
|
|
3240
3262
|
"platform",
|
|
3241
3263
|
"self",
|
|
3242
3264
|
"ack-redacted-source",
|
|
3265
|
+
"email",
|
|
3243
3266
|
"open",
|
|
3244
3267
|
"fail-on",
|
|
3245
3268
|
"fail-on-candidates",
|
|
@@ -3269,6 +3292,7 @@ async function runLocalSecurityCommand(parsed, dependencies) {
|
|
|
3269
3292
|
return getScopedPlatformToken({
|
|
3270
3293
|
platform: request.platform,
|
|
3271
3294
|
scope: request.scope,
|
|
3295
|
+
email: stringOpt(parsed.options.email),
|
|
3272
3296
|
open,
|
|
3273
3297
|
fetch: doFetch,
|
|
3274
3298
|
stdout: out,
|
|
@@ -3281,7 +3305,7 @@ async function runLocalSecurityCommand(parsed, dependencies) {
|
|
|
3281
3305
|
}
|
|
3282
3306
|
return getDeveloperToken(
|
|
3283
3307
|
cfg,
|
|
3284
|
-
{ configPath, open, openApprovalUrl: dependencies.openUrl },
|
|
3308
|
+
{ configPath, email: stringOpt(parsed.options.email), open, openApprovalUrl: dependencies.openUrl },
|
|
3285
3309
|
doFetch,
|
|
3286
3310
|
out
|
|
3287
3311
|
);
|
|
@@ -3315,7 +3339,7 @@ async function securityCommand(parsed, dependencies) {
|
|
|
3315
3339
|
return;
|
|
3316
3340
|
}
|
|
3317
3341
|
if (sub === "plan") {
|
|
3318
|
-
assertArgs(parsed, ["config", "env", "platform", "open", "json"], 2);
|
|
3342
|
+
assertArgs(parsed, ["config", "env", "platform", "email", "open", "json"], 2);
|
|
3319
3343
|
const context = await hostedSecurityContext(parsed, dependencies);
|
|
3320
3344
|
const plan = await getHostedSecurityPlan(context);
|
|
3321
3345
|
if (parsed.options.json === true) context.stdout.log(JSON.stringify(plan, null, 2));
|
|
@@ -3331,7 +3355,7 @@ async function securityCommand(parsed, dependencies) {
|
|
|
3331
3355
|
return;
|
|
3332
3356
|
}
|
|
3333
3357
|
if (sub === "report") {
|
|
3334
|
-
assertArgs(parsed, ["config", "env", "platform", "open", "json"], 3);
|
|
3358
|
+
assertArgs(parsed, ["config", "env", "platform", "email", "open", "json"], 3);
|
|
3335
3359
|
const jobId = requiredSecurityPositional(parsed, 2, "job id");
|
|
3336
3360
|
const context = await hostedSecurityContext(parsed, dependencies);
|
|
3337
3361
|
const report = await getHostedSecurityReport({ ...context, jobId });
|
|
@@ -3349,7 +3373,7 @@ async function securityCommand(parsed, dependencies) {
|
|
|
3349
3373
|
async function githubSecurityCommand(parsed, dependencies) {
|
|
3350
3374
|
const action = parsed.positionals[2];
|
|
3351
3375
|
if (action === "disconnect") {
|
|
3352
|
-
assertArgs(parsed, ["config", "env", "platform", "source", "open", "yes"], 3);
|
|
3376
|
+
assertArgs(parsed, ["config", "env", "platform", "source", "email", "open", "yes"], 3);
|
|
3353
3377
|
const context2 = await hostedSecurityContext(parsed, dependencies);
|
|
3354
3378
|
const sourceId = requiredString(parsed.options.source, "--source");
|
|
3355
3379
|
const confirmed = parsed.options.yes === true || await interactiveConfirmation(
|
|
@@ -3366,7 +3390,7 @@ async function githubSecurityCommand(parsed, dependencies) {
|
|
|
3366
3390
|
if (action !== "connect") {
|
|
3367
3391
|
throw new Error('unknown security github command. Try "odla-ai security github connect".');
|
|
3368
3392
|
}
|
|
3369
|
-
assertArgs(parsed, ["config", "env", "platform", "repo", "open"], 3);
|
|
3393
|
+
assertArgs(parsed, ["config", "env", "platform", "repo", "email", "open"], 3);
|
|
3370
3394
|
const context = await hostedSecurityContext(parsed, dependencies);
|
|
3371
3395
|
const repository = stringOpt(parsed.options.repo) ?? await inferGitHubRepository(process.cwd(), dependencies.readGitOrigin);
|
|
3372
3396
|
const connection = await connectGitHubSecuritySource({
|
|
@@ -3381,7 +3405,7 @@ async function githubSecurityCommand(parsed, dependencies) {
|
|
|
3381
3405
|
context.stdout.log("github: odla.ai stores the installation; no PAT or GitHub token is written locally");
|
|
3382
3406
|
}
|
|
3383
3407
|
async function listSecuritySources(parsed, dependencies) {
|
|
3384
|
-
assertArgs(parsed, ["config", "env", "platform", "open", "json"], 2);
|
|
3408
|
+
assertArgs(parsed, ["config", "env", "platform", "email", "open", "json"], 2);
|
|
3385
3409
|
const context = await hostedSecurityContext(parsed, dependencies);
|
|
3386
3410
|
const [plan, sources] = await Promise.all([
|
|
3387
3411
|
getHostedSecurityPlan(context),
|
|
@@ -3403,7 +3427,7 @@ source repository default ref status`);
|
|
|
3403
3427
|
}
|
|
3404
3428
|
}
|
|
3405
3429
|
async function securityStatus(parsed, dependencies) {
|
|
3406
|
-
assertArgs(parsed, ["config", "env", "platform", "open", "json", "follow"], 3);
|
|
3430
|
+
assertArgs(parsed, ["config", "env", "platform", "email", "open", "json", "follow"], 3);
|
|
3407
3431
|
const jobId = requiredSecurityPositional(parsed, 2, "job id");
|
|
3408
3432
|
const context = await hostedSecurityContext(parsed, dependencies);
|
|
3409
3433
|
const job = parsed.options.follow === true ? await followHostedSecurityJob({
|
|
@@ -3706,6 +3730,7 @@ async function smoke(options) {
|
|
|
3706
3730
|
{
|
|
3707
3731
|
configPath: cfg.configPath,
|
|
3708
3732
|
token: options.token,
|
|
3733
|
+
email: options.email,
|
|
3709
3734
|
open: options.open,
|
|
3710
3735
|
interactive: options.interactive,
|
|
3711
3736
|
openApprovalUrl: options.openApprovalUrl
|
|
@@ -3853,11 +3878,12 @@ async function runCli(argv = process.argv.slice(2), dependencies = {}) {
|
|
|
3853
3878
|
return;
|
|
3854
3879
|
}
|
|
3855
3880
|
if (command === "smoke") {
|
|
3856
|
-
assertArgs(parsed, ["config", "env", "token", "open"], 1);
|
|
3881
|
+
assertArgs(parsed, ["config", "env", "token", "email", "open"], 1);
|
|
3857
3882
|
await smoke({
|
|
3858
3883
|
configPath: stringOpt(parsed.options.config) ?? "odla.config.mjs",
|
|
3859
3884
|
env: stringOpt(parsed.options.env),
|
|
3860
3885
|
token: stringOpt(parsed.options.token),
|
|
3886
|
+
email: stringOpt(parsed.options.email),
|
|
3861
3887
|
open: parsed.options.open === false ? false : parsed.options.open === true ? true : void 0,
|
|
3862
3888
|
openApprovalUrl: dependencies.openUrl,
|
|
3863
3889
|
fetch: dependencies.fetch,
|
|
@@ -3895,7 +3921,7 @@ async function runCli(argv = process.argv.slice(2), dependencies = {}) {
|
|
|
3895
3921
|
if (command === "secrets") {
|
|
3896
3922
|
const sub = parsed.positionals[1];
|
|
3897
3923
|
if (sub === "set" || sub === "set-clerk-key") {
|
|
3898
|
-
assertArgs(parsed, ["config", "env", "from-env", "stdin", "token", "yes"], sub === "set" ? 3 : 2);
|
|
3924
|
+
assertArgs(parsed, ["config", "env", "from-env", "stdin", "token", "email", "yes"], sub === "set" ? 3 : 2);
|
|
3899
3925
|
const options = {
|
|
3900
3926
|
configPath: stringOpt(parsed.options.config) ?? "odla.config.mjs",
|
|
3901
3927
|
name: parsed.positionals[2],
|
|
@@ -3903,6 +3929,7 @@ async function runCli(argv = process.argv.slice(2), dependencies = {}) {
|
|
|
3903
3929
|
fromEnv: stringOpt(parsed.options["from-env"]),
|
|
3904
3930
|
stdin: parsed.options.stdin === true,
|
|
3905
3931
|
token: stringOpt(parsed.options.token),
|
|
3932
|
+
email: stringOpt(parsed.options.email),
|
|
3906
3933
|
yes: parsed.options.yes === true,
|
|
3907
3934
|
fetch: dependencies.fetch,
|
|
3908
3935
|
stdout: dependencies.stdout
|
|
@@ -3936,6 +3963,7 @@ async function provisionCommand(parsed, dependencies) {
|
|
|
3936
3963
|
"write-credentials",
|
|
3937
3964
|
"write-dev-vars",
|
|
3938
3965
|
"token",
|
|
3966
|
+
"email",
|
|
3939
3967
|
"open",
|
|
3940
3968
|
"yes"
|
|
3941
3969
|
], 1);
|
|
@@ -3949,6 +3977,7 @@ async function provisionCommand(parsed, dependencies) {
|
|
|
3949
3977
|
writeCredentials: parsed.options["write-credentials"] !== false,
|
|
3950
3978
|
writeDevVars: typeof writeDevVars2 === "string" ? writeDevVars2 : writeDevVars2 === true,
|
|
3951
3979
|
token: stringOpt(parsed.options.token),
|
|
3980
|
+
email: stringOpt(parsed.options.email),
|
|
3952
3981
|
open: parsed.options.open === false ? false : parsed.options.open === true ? true : void 0,
|
|
3953
3982
|
yes: parsed.options.yes === true,
|
|
3954
3983
|
fetch: dependencies.fetch,
|
|
@@ -3962,13 +3991,14 @@ async function calendarCommand(parsed, dependencies) {
|
|
|
3962
3991
|
if (sub !== "status" && sub !== "calendars" && sub !== "connect" && sub !== "resync" && sub !== "disconnect") {
|
|
3963
3992
|
throw new Error(`unknown calendar subcommand "${sub ?? ""}". Try "odla-ai calendar status --env dev".`);
|
|
3964
3993
|
}
|
|
3965
|
-
assertArgs(parsed, ["config", "env", "json", "token", "open", "yes"], 2);
|
|
3994
|
+
assertArgs(parsed, ["config", "env", "json", "token", "email", "open", "yes"], 2);
|
|
3966
3995
|
if (sub !== "status" && sub !== "calendars" && parsed.options.json !== void 0) throw new Error(`--json is supported only by calendar status/calendars`);
|
|
3967
3996
|
if ((sub === "status" || sub === "calendars") && parsed.options.yes !== void 0) throw new Error(`--yes is not used by "calendar ${sub}"`);
|
|
3968
3997
|
const options = {
|
|
3969
3998
|
configPath: stringOpt(parsed.options.config) ?? "odla.config.mjs",
|
|
3970
3999
|
env: stringOpt(parsed.options.env),
|
|
3971
4000
|
token: stringOpt(parsed.options.token),
|
|
4001
|
+
email: stringOpt(parsed.options.email),
|
|
3972
4002
|
open: parsed.options.open === false ? false : parsed.options.open === true ? true : void 0,
|
|
3973
4003
|
yes: parsed.options.yes === true,
|
|
3974
4004
|
json: parsed.options.json === true,
|