@odla-ai/cli 0.9.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 +108 -12
- package/REQUIREMENTS.md +31 -1
- package/dist/bin.cjs +743 -47
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-MJYQ7YDH.js → chunk-MWVKOIGR.js} +766 -62
- package/dist/chunk-MWVKOIGR.js.map +1 -0
- package/dist/index.cjs +759 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +204 -67
- package/dist/index.d.ts +204 -67
- package/dist/index.js +17 -1
- package/llms.txt +300 -80
- package/package.json +4 -4
- package/skills/odla/SKILL.md +19 -5
- package/skills/odla/references/build.md +24 -3
- package/skills/odla/references/sdks.md +29 -0
- package/skills/odla-migrate/SKILL.md +11 -2
- package/skills/odla-migrate/references/phase-2-db.md +8 -6
- package/skills/odla-migrate/references/phase-2b-calendar.md +42 -0
- 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-MJYQ7YDH.js.map +0 -1
package/llms.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @odla-ai/cli — LLM context
|
|
2
2
|
|
|
3
|
-
> Agent-operable CLI for odla provisioning, System AI administration,
|
|
3
|
+
> Agent-operable CLI for odla provisioning, calendar consent and sync lifecycle, System AI administration, Worker secrets, security jobs, and smoke checks.
|
|
4
4
|
|
|
5
5
|
> ⚠️ **Early access — pre-1.0.** Agents work from bounded runbooks; humans
|
|
6
6
|
> approve credentials, production changes, releases, and merges. APIs and exact
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
Project-neutral provisioning CLI for odla apps. It creates and validates an
|
|
11
11
|
`odla.config.mjs`, then uses that config to register an app, enable services,
|
|
12
12
|
push odla-db schema/rules, configure per-app BYOK AI, configure Clerk auth, record
|
|
13
|
-
deployment links, provision o11y ingest credentials, and transfer local or
|
|
13
|
+
deployment links, connect read-only Google Calendar mirrors, provision o11y ingest credentials, and transfer local or
|
|
14
14
|
deployed Worker secrets without printing them. It also gives platform admins a
|
|
15
15
|
scoped System AI control surface and gives app owners a provider-key-free
|
|
16
16
|
hosted security command.
|
|
@@ -31,13 +31,17 @@ For a project you keep working in, install it as a dev dependency so the
|
|
|
31
31
|
shorter `npx odla-ai` form works and the version is pinned by your lockfile:
|
|
32
32
|
|
|
33
33
|
```bash
|
|
34
|
-
npm view @odla-ai/cli@0.
|
|
35
|
-
npm i -D --save-exact @odla-ai/cli@0.
|
|
34
|
+
npm view @odla-ai/cli@0.10.1 version
|
|
35
|
+
npm i -D --save-exact @odla-ai/cli@0.10.1
|
|
36
36
|
```
|
|
37
37
|
|
|
38
38
|
## Prerequisites
|
|
39
39
|
|
|
40
40
|
- Node.js 20 or newer (`node --version`).
|
|
41
|
+
- An existing odla account that has signed in at least once. For any command
|
|
42
|
+
that may need a fresh device grant, pass `--email <account>` or set
|
|
43
|
+
`ODLA_USER_EMAIL`. This value identifies who may review the request; it is not
|
|
44
|
+
a password or session credential, and an agent must never ask for either.
|
|
41
45
|
- odla apps usually deploy as Cloudflare Workers. If you have never used
|
|
42
46
|
Cloudflare:
|
|
43
47
|
1. Create a free account at <https://dash.cloudflare.com/sign-up>.
|
|
@@ -55,10 +59,15 @@ npm i -D --save-exact @odla-ai/cli@0.9.0
|
|
|
55
59
|
npx odla-ai setup
|
|
56
60
|
npx odla-ai init --app-id my-app --name "My App"
|
|
57
61
|
npx odla-ai doctor
|
|
62
|
+
npx odla-ai calendar status --env dev
|
|
63
|
+
npx odla-ai calendar calendars --env dev
|
|
64
|
+
npx odla-ai calendar connect --env dev
|
|
65
|
+
npx odla-ai calendar resync --env dev
|
|
66
|
+
npx odla-ai calendar disconnect --env dev --yes
|
|
58
67
|
npx odla-ai capabilities --json
|
|
59
68
|
# install SDKs, write the Worker, and create wrangler.jsonc before secret push
|
|
60
69
|
npx odla-ai provision --dry-run
|
|
61
|
-
npx odla-ai provision --write-dev-vars --push-secrets
|
|
70
|
+
npx odla-ai provision --email owner@example.com --write-dev-vars --push-secrets
|
|
62
71
|
npx odla-ai smoke --env dev
|
|
63
72
|
npx odla-ai secrets push --env dev
|
|
64
73
|
npx odla-ai secrets set clerk_webhook_secret --env dev --stdin
|
|
@@ -70,7 +79,7 @@ npx @odla-ai/cli security sources --env dev
|
|
|
70
79
|
npx @odla-ai/cli security run --source <source-id> --ref main --env dev --plan-digest <digest-from-security-plan> --ack-redacted-source
|
|
71
80
|
npx @odla-ai/cli security status <job-id>
|
|
72
81
|
npx @odla-ai/cli security report <job-id>
|
|
73
|
-
npx odla-ai admin ai show
|
|
82
|
+
npx odla-ai admin ai show --email owner@example.com
|
|
74
83
|
npx odla-ai admin ai models
|
|
75
84
|
npx odla-ai admin ai set security --discovery-provider anthropic --discovery-model claude-opus-4-8 --validation-provider openai --validation-model gpt-5.5 --enabled
|
|
76
85
|
npx odla-ai admin ai credentials
|
|
@@ -98,21 +107,28 @@ When using `--push-secrets`, create the Worker and its Wrangler config first.
|
|
|
98
107
|
The CLI checks that config and `wrangler whoami` before it issues or rotates a
|
|
99
108
|
shown-once credential.
|
|
100
109
|
|
|
101
|
-
1. Gets an `odla_dev_...` token by device handshake, or reuses
|
|
102
|
-
`ODLA_DEV_TOKEN` / `.odla/dev-token.json`.
|
|
110
|
+
1. Gets an `odla_dev_...` token by email-bound device handshake, or reuses
|
|
111
|
+
`ODLA_DEV_TOKEN` / `.odla/dev-token.json`. A fresh handshake requires
|
|
112
|
+
`--email <account>` or `ODLA_USER_EMAIL`; the matching existing account must
|
|
113
|
+
sign in, review the exact code, and approve it. Opening the URL alone does
|
|
114
|
+
not claim the request.
|
|
103
115
|
In an interactive terminal it opens the approval page in your browser when
|
|
104
116
|
the code is displayed. Pass `--open` to force browser launch from a
|
|
105
117
|
non-interactive shell, or `--no-open` to suppress it. Browser launch is
|
|
106
118
|
best-effort; the printed URL and code always remain the fallback.
|
|
107
119
|
2. Creates the platform app if needed.
|
|
108
|
-
3. Enables configured services in every configured environment.
|
|
120
|
+
3. Enables configured services in every configured environment. Calendar
|
|
121
|
+
intent is normalized per env and fixed to Google read-only access.
|
|
109
122
|
4. Mints or reuses each env's configured service credentials: an odla-db app
|
|
110
123
|
key for `db` and an ingest token for `o11y`.
|
|
111
124
|
5. Pushes the configured schema and rules.
|
|
112
125
|
6. Configures platform AI and stores provider keys in the tenant vault when the
|
|
113
126
|
configured key env var is set.
|
|
114
|
-
7.
|
|
115
|
-
|
|
127
|
+
7. With calendar enabled, starts a separate state-bound Google consent attempt
|
|
128
|
+
when needed and follows it through initial sync. The human completes OAuth;
|
|
129
|
+
codes and tokens never enter the CLI, repository, chat, or app.
|
|
130
|
+
8. Writes `.odla/credentials.local.json` with mode `0600`.
|
|
131
|
+
9. With `--write-dev-vars`, writes the local Worker values to `.dev.vars`; with
|
|
116
132
|
`--push-secrets`, transfers the configured service secrets to the matching
|
|
117
133
|
deployed Worker environment over Wrangler stdin.
|
|
118
134
|
|
|
@@ -129,12 +145,65 @@ The CLI preflights Wrangler first and persists the replacement before pushing;
|
|
|
129
145
|
if that final push still fails, follow the printed `secrets push --env ...`
|
|
130
146
|
retry. Do not run the rotation flag again.
|
|
131
147
|
|
|
148
|
+
### Device-grant security and recovery
|
|
149
|
+
|
|
150
|
+
The account email sent during a fresh handshake is a non-secret identity hint,
|
|
151
|
+
not proof of identity. Unknown or never-signed-in accounts never produce a
|
|
152
|
+
claimable Studio request, and the public start/poll shape intentionally does not
|
|
153
|
+
reveal whether an account exists. The signed-in matching user must explicitly
|
|
154
|
+
review the exact code before it becomes pending, and only one claimed pending
|
|
155
|
+
or approved-but-uncollected request can be active for that user.
|
|
156
|
+
|
|
157
|
+
Developer grants are tracked by id, owner, label, scopes, creation/expiry,
|
|
158
|
+
last use, and revocation state. The plaintext token is delivered once to the
|
|
159
|
+
polling client and is never available from the inventory. Every signed-in user
|
|
160
|
+
can inspect and revoke their own grants under **Your agent credentials** in
|
|
161
|
+
Studio; platform admins additionally see the global token inventory and
|
|
162
|
+
metadata-only attempt evidence. Future requests with a revoked token fail.
|
|
163
|
+
Deleting
|
|
164
|
+
`.odla/dev-token.json` or `.odla/admin-token.local.json` removes the local copy
|
|
165
|
+
but does not revoke a token already copied elsewhere, so use Studio revocation
|
|
166
|
+
when compromise or accidental approval is possible.
|
|
167
|
+
|
|
132
168
|
`smoke` verifies a provisioned environment from local credentials. It fetches
|
|
133
169
|
the platform public config, checks the configured AI provider, fetches the live
|
|
134
170
|
odla-db schema with the tenant key, compares expected schema entities, and runs
|
|
135
171
|
a count aggregate against the first entity. It fails early with a clear message
|
|
136
172
|
when provisioning has not written `.odla/credentials.local.json`.
|
|
137
173
|
|
|
174
|
+
### Read-only Google Calendar
|
|
175
|
+
|
|
176
|
+
Calendar is a platform-custodied connector, not a Google credential stored by
|
|
177
|
+
the application. Enable both `db` and `calendar`, configure calendar ids and an
|
|
178
|
+
optional public Appointment Schedule `bookingPageUrl` per environment, then run
|
|
179
|
+
normal provision. The first run has two human checkpoints: the odla device code
|
|
180
|
+
establishes app-owner authority, then Google grants read-only Calendar scopes.
|
|
181
|
+
|
|
182
|
+
`calendar status --json` returns the safe connection/sync projection.
|
|
183
|
+
`calendar calendars --json` lists ids visible after consent; update checked-in
|
|
184
|
+
config and re-provision. A resulting `needs_sync` state reuses the installed
|
|
185
|
+
provider credential and resyncs without another OAuth attempt; an existing
|
|
186
|
+
authorization or initial sync is awaited rather than duplicated. `calendar
|
|
187
|
+
resync` requests an immediate sync, while
|
|
188
|
+
`calendar disconnect --yes` stops watches and deletes this app/environment
|
|
189
|
+
connection's encrypted platform token and cursors without purging retained
|
|
190
|
+
mirror rows, which therefore become stale. It does not revoke the shared
|
|
191
|
+
user-to-Google-OAuth-project grant, because that could invalidate other odla
|
|
192
|
+
connections for the same user. A future explicitly global revoke command would
|
|
193
|
+
need cross-connection accounting and warning. Production resync requires the
|
|
194
|
+
CLI's explicit `--yes` checkpoint, and disconnect always requires it. None of
|
|
195
|
+
these commands accepts a Google code, client secret, access token, or refresh
|
|
196
|
+
token.
|
|
197
|
+
|
|
198
|
+
The application uses its existing server-side `ODLA_ENDPOINT`, `ODLA_TENANT`,
|
|
199
|
+
and `ODLA_API_KEY`; calendar adds no app Worker secret. Never expose the app key
|
|
200
|
+
to a browser. Provider write actions are outside this read-only slice.
|
|
201
|
+
|
|
202
|
+
These commands operate the current read/embed reconciliation slice. The CLI has
|
|
203
|
+
no native slot-picker or create/reschedule/cancel command, and exposes no
|
|
204
|
+
rolling-window/age-out, quota-backoff, retention/purge, or provider-derived
|
|
205
|
+
mutation-id control. Public health remains aggregate rather than per calendar.
|
|
206
|
+
|
|
138
207
|
The bundled build/migration skills add a passive pre-ship gate with
|
|
139
208
|
`@odla-ai/security`: after the exact-version availability check, run
|
|
140
209
|
`npm i -D --save-exact @odla-ai/security@0.2.2`, then
|
|
@@ -342,7 +411,7 @@ export default {
|
|
|
342
411
|
dbEndpoint: process.env.ODLA_ENDPOINT ?? process.env.ODLA_DB_ENDPOINT ?? "https://db.odla.ai",
|
|
343
412
|
app: { id: "my-app", name: "My App" },
|
|
344
413
|
envs: ["dev"], // add "prod" deliberately; provisioning it requires --yes
|
|
345
|
-
services: ["db", "ai", "o11y"],
|
|
414
|
+
services: ["db", "ai", "o11y", "calendar"],
|
|
346
415
|
db: {
|
|
347
416
|
schema: "./src/odla/schema.mjs",
|
|
348
417
|
rules: "./src/odla/rules.mjs",
|
|
@@ -353,6 +422,20 @@ export default {
|
|
|
353
422
|
provider: process.env.ODLA_AI_PROVIDER ?? "anthropic",
|
|
354
423
|
keyEnv: "ANTHROPIC_API_KEY",
|
|
355
424
|
},
|
|
425
|
+
calendar: {
|
|
426
|
+
google: {
|
|
427
|
+
calendars: { dev: ["primary"] },
|
|
428
|
+
bookingPageUrl: {
|
|
429
|
+
dev: "https://calendar.google.com/calendar/appointments/schedules/…",
|
|
430
|
+
},
|
|
431
|
+
match: {
|
|
432
|
+
summaryPrefix: "Intro", // optional
|
|
433
|
+
organizerSelf: true,
|
|
434
|
+
requireAttendees: true,
|
|
435
|
+
},
|
|
436
|
+
attendeePolicy: "full", // or "hashed"
|
|
437
|
+
},
|
|
438
|
+
},
|
|
356
439
|
auth: {
|
|
357
440
|
// Publishable key (public). Created + pulled by the Clerk CLI (`npx clerk`);
|
|
358
441
|
// See the installed odla-migrate phase 3. Inline `pk_…` or "$ENV_VAR".
|
|
@@ -375,7 +458,7 @@ If schema is present and rules are omitted, `defaultRules: "deny"` generates
|
|
|
375
458
|
deny-all rules for every schema entity. That is the safe default for Workers
|
|
376
459
|
that mediate reads and writes with an app key.
|
|
377
460
|
|
|
378
|
-
## API reference (generated from dist/index.d.ts, v0.
|
|
461
|
+
## API reference (generated from dist/index.d.ts, v0.10.1)
|
|
379
462
|
|
|
380
463
|
```ts
|
|
381
464
|
import { SecurityReport, PlatformSecurityRun } from '@odla-ai/security';
|
|
@@ -410,6 +493,8 @@ type ScopedPlatformScope = "platform:ai:policy:read" | "platform:ai:policy:write
|
|
|
410
493
|
interface ScopedPlatformTokenOptions {
|
|
411
494
|
platform: string;
|
|
412
495
|
scope: ScopedPlatformScope;
|
|
496
|
+
/** Existing odla account email used only when a fresh handshake is required. */
|
|
497
|
+
email?: string;
|
|
413
498
|
open?: boolean;
|
|
414
499
|
fetch?: typeof fetch;
|
|
415
500
|
stdout?: Pick<typeof console, "log">;
|
|
@@ -439,6 +524,8 @@ interface AdminAiOptions {
|
|
|
439
524
|
maxCallsPerRun?: number;
|
|
440
525
|
platform?: string;
|
|
441
526
|
token?: string;
|
|
527
|
+
/** Existing odla account email used only when a fresh handshake is required. */
|
|
528
|
+
email?: string;
|
|
442
529
|
json?: boolean;
|
|
443
530
|
open?: boolean;
|
|
444
531
|
fetch?: typeof fetch;
|
|
@@ -471,79 +558,84 @@ declare function adminAi(options: AdminAiOptions): Promise<void>;
|
|
|
471
558
|
/** Stable, machine-readable division of work between the CLI, coding agent,
|
|
472
559
|
* human operator, and Studio. Printed by `odla-ai capabilities --json`. */
|
|
473
560
|
declare const CAPABILITIES: {
|
|
474
|
-
readonly cli: readonly ["register the app and enable configured services per environment", "issue, persist, and explicitly rotate configured service credentials", "write local Worker values and push deployed Worker secrets through Wrangler stdin", "store tenant-vault secrets (including the Clerk webhook secret and reserved Clerk secret key) write-only from stdin or an env var", "push db schema/rules and configure platform AI, auth, and deployment links", "validate config offline and smoke-test a provisioned db environment", "run app-attributed hosted security discovery and independent validation without provider keys", "connect/revoke source-read-only GitHub sources and drive commit-pinned hosted security jobs without PATs or provider keys", "let admins manage system AI policy and credentials, inspect attributed usage, and read immutable admin changes through separate short-lived capability-only approvals"];
|
|
475
|
-
readonly agent: readonly ["install and import the selected odla SDKs", "wrap the Worker with withObservability and choose useful telemetry", "make application-specific schema, rules, auth, UI, and migration decisions"];
|
|
476
|
-
readonly human: readonly ["
|
|
477
|
-
readonly studio: readonly ["view telemetry and environment state", "perform manual credential recovery when the CLI's local shown-once copy is unavailable", "configure system AI purposes and view app/environment/run-attributed usage", "connect/revoke GitHub security sources and inspect ref-to-SHA jobs, routes, retention, coverage, and normalized reports"];
|
|
561
|
+
readonly cli: readonly ["start an email-bound device request without accepting a password or user session token", "register the app and enable configured services per environment", "issue, persist, and explicitly rotate configured service credentials", "write local Worker values and push deployed Worker secrets through Wrangler stdin", "store tenant-vault secrets (including the Clerk webhook secret and reserved Clerk secret key) write-only from stdin or an env var", "push db schema/rules and configure platform AI, auth, and deployment links", "apply read-only Google calendar mirror and public booking-page config, then drive state-bound consent, status, discovery, resync, and disconnect flows", "validate config offline and smoke-test a provisioned db environment", "run app-attributed hosted security discovery and independent validation without provider keys", "connect/revoke source-read-only GitHub sources and drive commit-pinned hosted security jobs without PATs or provider keys", "let admins manage system AI policy and credentials, inspect attributed usage, and read immutable admin changes through separate short-lived capability-only approvals"];
|
|
562
|
+
readonly agent: readonly ["install and import the selected odla SDKs", "wrap the Worker with withObservability and choose useful telemetry", "make application-specific schema, rules, auth, UI, and migration decisions", "wire @odla-ai/calendar into trusted Worker code and keep the app admin key out of browsers"];
|
|
563
|
+
readonly human: readonly ["provide the existing odla account email, then sign in and explicitly review/approve the exact device code", "review mirrored calendar/attendee disclosure and complete the server-issued Google consent flow", "consent to production changes with --yes", "request destructive credential rotation explicitly", "review application semantics, security findings, releases, and merges", "approve redacted-source disclosure before hosted security reasoning", "approve GitHub App repository access separately from redacted-snippet disclosure"];
|
|
564
|
+
readonly studio: readonly ["view telemetry and environment state", "let signed-in users inventory/revoke their own agent grants and admins audit/global-revoke them", "review calendar connection, granted read scope, selected calendars, and sync health without exposing provider tokens", "perform manual credential recovery when the CLI's local shown-once copy is unavailable", "configure system AI purposes and view app/environment/run-attributed usage", "connect/revoke GitHub security sources and inspect ref-to-SHA jobs, routes, retention, coverage, and normalized reports"];
|
|
478
565
|
};
|
|
479
566
|
type Output = Pick<typeof console, "log">;
|
|
480
567
|
/** Print the stable responsibility boundary for humans or agent tooling. */
|
|
481
568
|
declare function printCapabilities(json?: boolean, out?: Output): void;
|
|
482
569
|
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
570
|
+
declare const CALENDAR_STATES: readonly ["not_connected", "authorizing", "needs_sync", "initial_sync", "healthy", "degraded", "disconnected", "failed"];
|
|
571
|
+
/** Connection lifecycle reported by the registry; mirrors the platform's calendar states. */
|
|
572
|
+
type CalendarConnectionState = (typeof CALENDAR_STATES)[number];
|
|
573
|
+
/** Owner-visible, secret-free calendar connection and sync health. */
|
|
574
|
+
interface CalendarStatus {
|
|
575
|
+
env: string;
|
|
576
|
+
enabled: boolean;
|
|
577
|
+
/** True when the platform has provider credentials for this connection. */
|
|
578
|
+
connected: boolean;
|
|
579
|
+
provider: "google" | null;
|
|
580
|
+
status: CalendarConnectionState;
|
|
581
|
+
access?: "read";
|
|
582
|
+
calendars: string[];
|
|
583
|
+
attendeePolicy?: "full" | "hashed";
|
|
584
|
+
/** True once a booking projection may have established the DB privacy policy. */
|
|
585
|
+
attendeePolicyLocked?: boolean;
|
|
586
|
+
bookingPageUrl?: string | null;
|
|
587
|
+
grantedScopes: string[];
|
|
588
|
+
attemptId?: string;
|
|
589
|
+
lastSuccessfulSyncAt?: number;
|
|
590
|
+
lastFullSyncAt?: number;
|
|
591
|
+
watchExpiresAt?: number;
|
|
592
|
+
bookingCount?: number;
|
|
593
|
+
error?: {
|
|
594
|
+
code?: string;
|
|
595
|
+
message?: string;
|
|
596
|
+
};
|
|
597
|
+
}
|
|
598
|
+
/** One Google calendar the connected identity may select for mirroring. */
|
|
599
|
+
interface AvailableGoogleCalendar {
|
|
600
|
+
id: string;
|
|
601
|
+
summary?: string;
|
|
602
|
+
primary?: boolean;
|
|
603
|
+
selected?: boolean;
|
|
604
|
+
accessRole?: "freeBusyReader" | "reader" | "writer" | "owner";
|
|
486
605
|
}
|
|
487
|
-
/**
|
|
488
|
-
* Validate and summarize an odla project config entirely offline — no network
|
|
489
|
-
* calls and no file writes. Loads `configPath`, builds the provision plan, and
|
|
490
|
-
* resolves the schema and rules (synthesizing deny-all rules from the schema
|
|
491
|
-
* when `db.rules` is omitted and `db.defaultRules` isn't `false`), then prints a
|
|
492
|
-
* summary line for the app, envs, services, schema entity count, rules namespace
|
|
493
|
-
* count, and AI provider.
|
|
494
|
-
*
|
|
495
|
-
* It then collects warnings for the mistakes provision can't fix silently: a
|
|
496
|
-
* schema with no entities, a rules namespace with no matching entity, the `ai`
|
|
497
|
-
* service enabled without an `ai.provider`, `auth.clerk` entries that reference
|
|
498
|
-
* an unset env var (`$FOO`), an `ai.keyEnv` that isn't set (provider key upload
|
|
499
|
-
* will be skipped), and — when `o11y` is enabled — any env whose local
|
|
500
|
-
* credentials lack an ingest token. It also folds in the shared rule linter,
|
|
501
|
-
* git-tracked secret-shaped files, and wrangler config warnings. Prints `ok`
|
|
502
|
-
* when clean, otherwise the warning list. Purely advisory: never throws on
|
|
503
|
-
* warnings and never mutates anything.
|
|
504
|
-
*
|
|
505
|
-
* @param options.configPath Path to the `odla.config.mjs` to inspect.
|
|
506
|
-
* @param options.stdout Optional console-like sink (defaults to `console`).
|
|
507
|
-
*/
|
|
508
|
-
declare function doctor(options: DoctorOptions): Promise<void>;
|
|
509
606
|
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
607
|
+
/** Shared inputs for the calendar lifecycle commands (status, connect,
|
|
608
|
+
* calendars, resync, disconnect): the project config path and env, plus
|
|
609
|
+
* injectable token, output, browser, clock, and polling hooks so agents and
|
|
610
|
+
* tests can drive the flow deterministically. */
|
|
611
|
+
interface CalendarLifecycleOptions {
|
|
612
|
+
/** Path to the checked-in odla project config. */ configPath: string;
|
|
613
|
+
/** Configured environment; defaults to dev when present. */ env?: string;
|
|
614
|
+
/** Existing developer-token override. */ token?: string;
|
|
615
|
+
/** Existing odla account email used only for a fresh handshake. */ email?: string;
|
|
616
|
+
open?: boolean;
|
|
617
|
+
interactive?: boolean;
|
|
618
|
+
yes?: boolean;
|
|
619
|
+
json?: boolean;
|
|
620
|
+
fetch?: typeof fetch;
|
|
519
621
|
stdout?: Pick<typeof console, "log" | "error">;
|
|
622
|
+
openConsentUrl?: (url: string) => Promise<void>;
|
|
623
|
+
wait?: (milliseconds: number, signal?: AbortSignal) => Promise<void>;
|
|
624
|
+
pollTimeoutMs?: number;
|
|
625
|
+
now?: () => number;
|
|
626
|
+
signal?: AbortSignal;
|
|
520
627
|
}
|
|
521
|
-
/**
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
*
|
|
531
|
-
|
|
532
|
-
* it throws. Defaults: `envs` → `["dev"]`, `services` → `["db","ai"]`,
|
|
533
|
-
* `aiProvider` → `"anthropic"` (which also picks the `keyEnv`, e.g.
|
|
534
|
-
* `ANTHROPIC_API_KEY`/`OPENAI_API_KEY`/`GOOGLE_API_KEY`).
|
|
535
|
-
*
|
|
536
|
-
* @param options.appId Slug for the app (lowercase alphanumerics and hyphens).
|
|
537
|
-
* @param options.name Human-readable app name embedded in the config.
|
|
538
|
-
* @param options.rootDir Project root (defaults to `process.cwd()`).
|
|
539
|
-
* @param options.configPath Config filename relative to root (default `odla.config.mjs`).
|
|
540
|
-
* @param options.envs Environment names (default `["dev"]`; production is an explicit opt-in).
|
|
541
|
-
* @param options.services Enabled services (default `["db","ai"]`).
|
|
542
|
-
* @param options.aiProvider AI provider slug (default `"anthropic"`).
|
|
543
|
-
* @param options.force Overwrite an existing config file instead of throwing.
|
|
544
|
-
* @param options.stdout Optional console-like sink (defaults to `console`).
|
|
545
|
-
*/
|
|
546
|
-
declare function initProject(options: InitOptions): void;
|
|
628
|
+
/** Read the owner-visible Google connection and mirror health for one env. */
|
|
629
|
+
declare function calendarStatus(options: CalendarLifecycleOptions): Promise<CalendarStatus>;
|
|
630
|
+
/** List calendars visible to the connected Google identity for config authoring. */
|
|
631
|
+
declare function calendarCalendars(options: CalendarLifecycleOptions): Promise<AvailableGoogleCalendar[]>;
|
|
632
|
+
/** Apply the public booking page setting, then complete Google consent + initial sync. */
|
|
633
|
+
declare function calendarConnect(options: CalendarLifecycleOptions): Promise<CalendarStatus>;
|
|
634
|
+
/** Ask the hosted connector for an immediate incremental/full recovery sync. */
|
|
635
|
+
declare function calendarResync(options: CalendarLifecycleOptions): Promise<CalendarStatus>;
|
|
636
|
+
/** Stop watches and delete this connection's encrypted platform token/cursors
|
|
637
|
+
* without purging the mirror or revoking the shared Google project grant. */
|
|
638
|
+
declare function calendarDisconnect(options: CalendarLifecycleOptions): Promise<CalendarStatus>;
|
|
547
639
|
|
|
548
640
|
interface RunResult {
|
|
549
641
|
code: number;
|
|
@@ -568,6 +660,43 @@ interface ClerkAuthConfig {
|
|
|
568
660
|
audience?: string;
|
|
569
661
|
mode?: "client" | "full";
|
|
570
662
|
}
|
|
663
|
+
/** Read-only event selection applied by the hosted Google calendar connector. */
|
|
664
|
+
interface GoogleCalendarMatchConfig {
|
|
665
|
+
/** Mirror only events whose summary begins with this value. */
|
|
666
|
+
summaryPrefix?: string;
|
|
667
|
+
/** Require the connected identity to organize the event. Defaults to true. */
|
|
668
|
+
organizerSelf?: boolean;
|
|
669
|
+
/** Require at least one attendee. Defaults to true. */
|
|
670
|
+
requireAttendees?: boolean;
|
|
671
|
+
}
|
|
672
|
+
/** Google Calendar intent. OAuth credentials never belong in this config. */
|
|
673
|
+
interface GoogleCalendarConfig {
|
|
674
|
+
/** One through ten provider calendar ids to mirror in each odla environment. */
|
|
675
|
+
calendars: Record<OdlaEnvName, string[]>;
|
|
676
|
+
/** Public Google Appointment Schedule URL for static embed/link mode. */
|
|
677
|
+
bookingPageUrl?: Record<OdlaEnvName, string | null>;
|
|
678
|
+
match?: GoogleCalendarMatchConfig;
|
|
679
|
+
/** Store normalized attendee addresses, or only SHA-256 match keys. */
|
|
680
|
+
attendeePolicy?: "full" | "hashed";
|
|
681
|
+
}
|
|
682
|
+
/** The `calendar` block of `odla.config.mjs` — the Google read-mirror
|
|
683
|
+
* settings; valid only alongside the db service. */
|
|
684
|
+
interface CalendarConfig {
|
|
685
|
+
google: GoogleCalendarConfig;
|
|
686
|
+
}
|
|
687
|
+
/** Canonical, environment-specific config sent to the calendar controller. */
|
|
688
|
+
interface CalendarServiceConfig extends Record<string, unknown> {
|
|
689
|
+
provider: "google";
|
|
690
|
+
access: "read";
|
|
691
|
+
/** Deduplicated provider ids; the hosted connector accepts at most ten. */
|
|
692
|
+
calendars: string[];
|
|
693
|
+
match: {
|
|
694
|
+
organizerSelf: boolean;
|
|
695
|
+
requireAttendees: boolean;
|
|
696
|
+
summaryPrefix?: string;
|
|
697
|
+
};
|
|
698
|
+
attendeePolicy: "full" | "hashed";
|
|
699
|
+
}
|
|
571
700
|
/** Authored `odla.config.mjs` contract consumed by doctor and provision. */
|
|
572
701
|
interface OdlaProjectConfig {
|
|
573
702
|
platformUrl?: string;
|
|
@@ -596,6 +725,7 @@ interface OdlaProjectConfig {
|
|
|
596
725
|
/** Vault secret name. Defaults to @odla-ai/ai's provider default. */
|
|
597
726
|
secretName?: string;
|
|
598
727
|
};
|
|
728
|
+
calendar?: CalendarConfig;
|
|
599
729
|
o11y?: {
|
|
600
730
|
/** This service's name in the collector. Defaults to the app id. */
|
|
601
731
|
service?: string;
|
|
@@ -654,12 +784,18 @@ interface ProvisionOptions {
|
|
|
654
784
|
writeCredentials?: boolean;
|
|
655
785
|
writeDevVars?: string | boolean;
|
|
656
786
|
token?: string;
|
|
787
|
+
/** Existing odla account email used only when a fresh device handshake is required. */
|
|
788
|
+
email?: string;
|
|
657
789
|
/** true forces browser launch, false disables it, undefined auto-opens only for interactive terminals. */
|
|
658
790
|
open?: boolean;
|
|
659
791
|
/** Test/embedding override for terminal interactivity. Defaults to stdin/stdout TTY detection. */
|
|
660
792
|
interactive?: boolean;
|
|
661
793
|
/** Test/embedding override for opening the approval URL. Defaults to the OS browser opener. */
|
|
662
794
|
openApprovalUrl?: (url: string) => Promise<void>;
|
|
795
|
+
/** Test/embedding override for calendar connection polling. */
|
|
796
|
+
calendarPollWait?: (milliseconds: number, signal?: AbortSignal) => Promise<void>;
|
|
797
|
+
/** Maximum calendar consent + initial-sync wait. Defaults to ten minutes. */
|
|
798
|
+
calendarPollTimeoutMs?: number;
|
|
663
799
|
/** Explicit consent for a non-dry-run plan containing `prod` or `production`. */
|
|
664
800
|
yes?: boolean;
|
|
665
801
|
fetch?: typeof fetch;
|
|
@@ -683,10 +819,89 @@ interface ProvisionPlan {
|
|
|
683
819
|
interface SmokeOptions {
|
|
684
820
|
configPath: string;
|
|
685
821
|
env?: string;
|
|
822
|
+
/** Developer-token override used only for owner-visible calendar health. */
|
|
823
|
+
token?: string;
|
|
824
|
+
/** Existing odla account email used only when a fresh device handshake is required. */
|
|
825
|
+
email?: string;
|
|
826
|
+
open?: boolean;
|
|
827
|
+
interactive?: boolean;
|
|
828
|
+
openApprovalUrl?: (url: string) => Promise<void>;
|
|
686
829
|
fetch?: typeof fetch;
|
|
687
830
|
stdout?: Pick<typeof console, "log" | "error">;
|
|
688
831
|
}
|
|
689
832
|
|
|
833
|
+
/** The only Google OAuth scope the platform ever requests: read-only calendar events. */
|
|
834
|
+
declare const GOOGLE_CALENDAR_READ_SCOPE = "https://www.googleapis.com/auth/calendar.events.readonly";
|
|
835
|
+
/** Resolve the checked-in calendar block into one controller-safe env payload. */
|
|
836
|
+
declare function calendarServiceConfig(cfg: LoadedProjectConfig, env: string): CalendarServiceConfig;
|
|
837
|
+
/** Public Appointment Schedule URL to apply separately from connector config. */
|
|
838
|
+
declare function calendarBookingPageUrl(cfg: LoadedProjectConfig, env: string): string | null | undefined;
|
|
839
|
+
|
|
840
|
+
interface DoctorOptions {
|
|
841
|
+
configPath: string;
|
|
842
|
+
stdout?: Pick<typeof console, "log" | "error">;
|
|
843
|
+
}
|
|
844
|
+
/**
|
|
845
|
+
* Validate and summarize an odla project config entirely offline — no network
|
|
846
|
+
* calls and no file writes. Loads `configPath`, builds the provision plan, and
|
|
847
|
+
* resolves the schema and rules (synthesizing deny-all rules from the schema
|
|
848
|
+
* when `db.rules` is omitted and `db.defaultRules` isn't `false`), then prints a
|
|
849
|
+
* summary line for the app, envs, services, schema entity count, rules namespace
|
|
850
|
+
* count, and AI provider.
|
|
851
|
+
*
|
|
852
|
+
* It then collects warnings for the mistakes provision can't fix silently: a
|
|
853
|
+
* schema with no entities, a rules namespace with no matching entity, the `ai`
|
|
854
|
+
* service enabled without an `ai.provider`, `auth.clerk` entries that reference
|
|
855
|
+
* an unset env var (`$FOO`), an `ai.keyEnv` that isn't set (provider key upload
|
|
856
|
+
* will be skipped), and — when `o11y` is enabled — any env whose local
|
|
857
|
+
* credentials lack an ingest token. It also folds in the shared rule linter,
|
|
858
|
+
* git-tracked secret-shaped files, and wrangler config warnings. Prints `ok`
|
|
859
|
+
* when clean, otherwise the warning list. Purely advisory: never throws on
|
|
860
|
+
* warnings and never mutates anything.
|
|
861
|
+
*
|
|
862
|
+
* @param options.configPath Path to the `odla.config.mjs` to inspect.
|
|
863
|
+
* @param options.stdout Optional console-like sink (defaults to `console`).
|
|
864
|
+
*/
|
|
865
|
+
declare function doctor(options: DoctorOptions): Promise<void>;
|
|
866
|
+
|
|
867
|
+
interface InitOptions {
|
|
868
|
+
rootDir?: string;
|
|
869
|
+
configPath?: string;
|
|
870
|
+
appId: string;
|
|
871
|
+
name: string;
|
|
872
|
+
envs?: string[];
|
|
873
|
+
services?: string[];
|
|
874
|
+
aiProvider?: string;
|
|
875
|
+
force?: boolean;
|
|
876
|
+
stdout?: Pick<typeof console, "log" | "error">;
|
|
877
|
+
}
|
|
878
|
+
/**
|
|
879
|
+
* Scaffold a new odla project into `rootDir` (default: cwd). Writes an
|
|
880
|
+
* `odla.config.mjs` (default name, overridable via `configPath`) plus starter
|
|
881
|
+
* `src/odla/schema.mjs` (a single `notes` entity) and `src/odla/rules.mjs`
|
|
882
|
+
* (deny-all), and creates the `src/odla` and `.odla` directories. Also runs
|
|
883
|
+
* `ensureGitignore` so the local token/credentials paths are ignored.
|
|
884
|
+
*
|
|
885
|
+
* Fully local and synchronous — no network calls. The config file is only
|
|
886
|
+
* written when it doesn't already exist unless `force` is set (otherwise it
|
|
887
|
+
* throws); the schema/rules files are written only when missing (never
|
|
888
|
+
* overwritten, even with `force`). `appId` must match `^[a-z0-9][a-z0-9-]*$` or
|
|
889
|
+
* it throws. Defaults: `envs` → `["dev"]`, `services` → `["db","ai"]`,
|
|
890
|
+
* `aiProvider` → `"anthropic"` (which also picks the `keyEnv`, e.g.
|
|
891
|
+
* `ANTHROPIC_API_KEY`/`OPENAI_API_KEY`/`GOOGLE_API_KEY`).
|
|
892
|
+
*
|
|
893
|
+
* @param options.appId Slug for the app (lowercase alphanumerics and hyphens).
|
|
894
|
+
* @param options.name Human-readable app name embedded in the config.
|
|
895
|
+
* @param options.rootDir Project root (defaults to `process.cwd()`).
|
|
896
|
+
* @param options.configPath Config filename relative to root (default `odla.config.mjs`).
|
|
897
|
+
* @param options.envs Environment names (default `["dev"]`; production is an explicit opt-in).
|
|
898
|
+
* @param options.services Enabled services (default `["db","ai"]`).
|
|
899
|
+
* @param options.aiProvider AI provider slug (default `"anthropic"`).
|
|
900
|
+
* @param options.force Overwrite an existing config file instead of throwing.
|
|
901
|
+
* @param options.stdout Optional console-like sink (defaults to `console`).
|
|
902
|
+
*/
|
|
903
|
+
declare function initProject(options: InitOptions): void;
|
|
904
|
+
|
|
690
905
|
/**
|
|
691
906
|
* Provision an app end-to-end from its config — the primary deploy path, and
|
|
692
907
|
* (apart from key rotation) idempotent, so re-running is safe. Obtains a
|
|
@@ -699,14 +914,17 @@ interface SmokeOptions {
|
|
|
699
914
|
* (mode 0600, gitignored) and, when requested, `.dev.vars`.
|
|
700
915
|
*
|
|
701
916
|
* The developer token comes from (in order) `options.token`, `$ODLA_DEV_TOKEN`,
|
|
702
|
-
* the cached `.odla` token, or a fresh device handshake — which
|
|
703
|
-
* code
|
|
917
|
+
* the cached `.odla` token, or a fresh email-bound device handshake — which
|
|
918
|
+
* prints a user code for the same signed-in account to review and, in
|
|
919
|
+
* interactive terminals, auto-opens the browser
|
|
704
920
|
* (`open: true`/`false` forces/suppresses it). Network error bodies pass through
|
|
705
921
|
* `redactSecrets` before display.
|
|
706
922
|
*
|
|
707
923
|
* @param options.dryRun Print the resolved plan and return before any network call/write.
|
|
708
924
|
* @param options.rotateKeys Rotate db keys and o11y tokens.
|
|
709
925
|
* @param options.rotateO11yToken Rotate only the o11y token.
|
|
926
|
+
* @param options.email Existing odla account email for a fresh handshake;
|
|
927
|
+
* this is an identity hint, never a password or session credential.
|
|
710
928
|
* @param options.pushSecrets Preflight Wrangler, then push each env's configured
|
|
711
929
|
* Worker secrets immediately after credential provisioning.
|
|
712
930
|
* @param options.writeDevVars `true`/a path writes `.dev.vars`; `writeCredentials: false` skips the creds file.
|
|
@@ -764,6 +982,8 @@ interface SecretsSetOptions {
|
|
|
764
982
|
yes?: boolean;
|
|
765
983
|
/** Developer token override; defaults to $ODLA_DEV_TOKEN, the cached token, or a device handshake. */
|
|
766
984
|
token?: string;
|
|
985
|
+
/** Existing odla account email used only when a fresh handshake is required. */
|
|
986
|
+
email?: string;
|
|
767
987
|
open?: boolean;
|
|
768
988
|
interactive?: boolean;
|
|
769
989
|
openApprovalUrl?: (url: string) => Promise<void>;
|
|
@@ -1046,5 +1266,5 @@ declare function installSkill(options?: SkillInstallOptions): SkillInstallResult
|
|
|
1046
1266
|
*/
|
|
1047
1267
|
declare function smoke(options: SmokeOptions): Promise<void>;
|
|
1048
1268
|
|
|
1049
|
-
export { AGENT_HARNESSES, type AdminAiOptions, type AgentHarness, type AgentHarnessSelector, CAPABILITIES, type CliDependencies, type ConnectGitHubSecuritySourceOptions, type DisconnectGitHubSecuritySourceOptions, type FollowHostedSecurityJobOptions, type GetHostedSecurityIntentOptions, type GetHostedSecurityJobOptions, type HarnessInstallResult, type HostedSecurityProfile, type HostedSecurityResult, type HostedSecurityTokenRequest, type ListGitHubSecuritySourcesOptions, type ListHostedSecurityJobsOptions, type LoadedProjectConfig, type LocalCredentials, type OdlaProjectConfig, type ProvisionOptions, type ProvisionPlan, type RunHostedSecurityOptions, SYSTEM_AI_PURPOSES, type ScopedPlatformTokenOptions, type SecretsPushOptions, type SecretsSetOptions, type SkillInstallOptions, type SkillInstallResult, type SmokeOptions, type StartHostedSecurityJobOptions, type SystemAiPurpose, adminAi, connectGitHubSecuritySource, disconnectGitHubSecuritySource, doctor, followHostedSecurityJob, getHostedSecurityIntent, getHostedSecurityJob, getHostedSecurityPlan, getHostedSecurityReport, getScopedPlatformToken, inferGitHubRepository, initProject, installSkill, isTerminalHostedSecurityStatus, listGitHubSecuritySources, listHostedSecurityJobs, printCapabilities, provision, redactSecrets, repositoryFromGitRemote, runCli, runHostedSecurity, secretsPush, secretsSet, secretsSetClerkKey, smoke, startHostedSecurityJob };
|
|
1269
|
+
export { AGENT_HARNESSES, type AdminAiOptions, type AgentHarness, type AgentHarnessSelector, type AvailableGoogleCalendar, CAPABILITIES, type CalendarConfig, type CalendarConnectionState, type CalendarLifecycleOptions, type CalendarServiceConfig, type CalendarStatus, type CliDependencies, type ConnectGitHubSecuritySourceOptions, type DisconnectGitHubSecuritySourceOptions, type FollowHostedSecurityJobOptions, GOOGLE_CALENDAR_READ_SCOPE, type GetHostedSecurityIntentOptions, type GetHostedSecurityJobOptions, type GoogleCalendarConfig, type GoogleCalendarMatchConfig, type HarnessInstallResult, type HostedSecurityProfile, type HostedSecurityResult, type HostedSecurityTokenRequest, type ListGitHubSecuritySourcesOptions, type ListHostedSecurityJobsOptions, type LoadedProjectConfig, type LocalCredentials, type OdlaProjectConfig, type ProvisionOptions, type ProvisionPlan, type RunHostedSecurityOptions, SYSTEM_AI_PURPOSES, type ScopedPlatformTokenOptions, type SecretsPushOptions, type SecretsSetOptions, type SkillInstallOptions, type SkillInstallResult, type SmokeOptions, type StartHostedSecurityJobOptions, type SystemAiPurpose, adminAi, calendarBookingPageUrl, calendarCalendars, calendarConnect, calendarDisconnect, calendarResync, calendarServiceConfig, calendarStatus, connectGitHubSecuritySource, disconnectGitHubSecuritySource, doctor, followHostedSecurityJob, getHostedSecurityIntent, getHostedSecurityJob, getHostedSecurityPlan, getHostedSecurityReport, getScopedPlatformToken, inferGitHubRepository, initProject, installSkill, isTerminalHostedSecurityStatus, listGitHubSecuritySources, listHostedSecurityJobs, printCapabilities, provision, redactSecrets, repositoryFromGitRemote, runCli, runHostedSecurity, secretsPush, secretsSet, secretsSetClerkKey, smoke, startHostedSecurityJob };
|
|
1050
1270
|
```
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@odla-ai/cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Agent-operable CLI for odla provisioning, System AI administration,
|
|
3
|
+
"version": "0.10.1",
|
|
4
|
+
"description": "Agent-operable CLI for odla provisioning, calendar consent and sync lifecycle, System AI administration, Worker secrets, security jobs, and smoke checks.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://odla.ai/docs/packages/cli",
|
|
7
7
|
"repository": {
|
|
@@ -60,8 +60,8 @@
|
|
|
60
60
|
},
|
|
61
61
|
"dependencies": {
|
|
62
62
|
"@odla-ai/ai": "^0.3.3",
|
|
63
|
-
"@odla-ai/apps": "^0.
|
|
64
|
-
"@odla-ai/db": "^0.6.
|
|
63
|
+
"@odla-ai/apps": "^0.8.0",
|
|
64
|
+
"@odla-ai/db": "^0.6.3",
|
|
65
65
|
"@odla-ai/security": "^0.2.2"
|
|
66
66
|
},
|
|
67
67
|
"devDependencies": {
|