@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/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
Project-neutral provisioning CLI for odla apps. It creates and validates an
|
|
9
9
|
`odla.config.mjs`, then uses that config to register an app, enable services,
|
|
10
10
|
push odla-db schema/rules, configure per-app BYOK AI, configure Clerk auth, record
|
|
11
|
-
deployment links, provision o11y ingest credentials, and transfer local or
|
|
11
|
+
deployment links, connect read-only Google Calendar mirrors, provision o11y ingest credentials, and transfer local or
|
|
12
12
|
deployed Worker secrets without printing them. It also gives platform admins a
|
|
13
13
|
scoped System AI control surface and gives app owners a provider-key-free
|
|
14
14
|
hosted security command.
|
|
@@ -29,13 +29,17 @@ For a project you keep working in, install it as a dev dependency so the
|
|
|
29
29
|
shorter `npx odla-ai` form works and the version is pinned by your lockfile:
|
|
30
30
|
|
|
31
31
|
```bash
|
|
32
|
-
npm view @odla-ai/cli@0.
|
|
33
|
-
npm i -D --save-exact @odla-ai/cli@0.
|
|
32
|
+
npm view @odla-ai/cli@0.10.1 version
|
|
33
|
+
npm i -D --save-exact @odla-ai/cli@0.10.1
|
|
34
34
|
```
|
|
35
35
|
|
|
36
36
|
## Prerequisites
|
|
37
37
|
|
|
38
38
|
- Node.js 20 or newer (`node --version`).
|
|
39
|
+
- An existing odla account that has signed in at least once. For any command
|
|
40
|
+
that may need a fresh device grant, pass `--email <account>` or set
|
|
41
|
+
`ODLA_USER_EMAIL`. This value identifies who may review the request; it is not
|
|
42
|
+
a password or session credential, and an agent must never ask for either.
|
|
39
43
|
- odla apps usually deploy as Cloudflare Workers. If you have never used
|
|
40
44
|
Cloudflare:
|
|
41
45
|
1. Create a free account at <https://dash.cloudflare.com/sign-up>.
|
|
@@ -53,10 +57,15 @@ npm i -D --save-exact @odla-ai/cli@0.9.0
|
|
|
53
57
|
npx odla-ai setup
|
|
54
58
|
npx odla-ai init --app-id my-app --name "My App"
|
|
55
59
|
npx odla-ai doctor
|
|
60
|
+
npx odla-ai calendar status --env dev
|
|
61
|
+
npx odla-ai calendar calendars --env dev
|
|
62
|
+
npx odla-ai calendar connect --env dev
|
|
63
|
+
npx odla-ai calendar resync --env dev
|
|
64
|
+
npx odla-ai calendar disconnect --env dev --yes
|
|
56
65
|
npx odla-ai capabilities --json
|
|
57
66
|
# install SDKs, write the Worker, and create wrangler.jsonc before secret push
|
|
58
67
|
npx odla-ai provision --dry-run
|
|
59
|
-
npx odla-ai provision --write-dev-vars --push-secrets
|
|
68
|
+
npx odla-ai provision --email owner@example.com --write-dev-vars --push-secrets
|
|
60
69
|
npx odla-ai smoke --env dev
|
|
61
70
|
npx odla-ai secrets push --env dev
|
|
62
71
|
npx odla-ai secrets set clerk_webhook_secret --env dev --stdin
|
|
@@ -68,7 +77,7 @@ npx odla-ai security sources --env dev
|
|
|
68
77
|
npx odla-ai security run --source <source-id> --ref main --env dev --plan-digest <digest-from-security-plan> --ack-redacted-source
|
|
69
78
|
npx odla-ai security status <job-id>
|
|
70
79
|
npx odla-ai security report <job-id>
|
|
71
|
-
npx odla-ai admin ai show
|
|
80
|
+
npx odla-ai admin ai show --email owner@example.com
|
|
72
81
|
npx odla-ai admin ai models
|
|
73
82
|
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
|
|
74
83
|
npx odla-ai admin ai credentials
|
|
@@ -96,21 +105,30 @@ When using `--push-secrets`, create the Worker and its Wrangler config first.
|
|
|
96
105
|
The CLI checks that config and `wrangler whoami` before it issues or rotates a
|
|
97
106
|
shown-once credential.
|
|
98
107
|
|
|
99
|
-
1. Gets an `odla_dev_...` token by device handshake, or reuses
|
|
100
|
-
`ODLA_DEV_TOKEN` / `.odla/dev-token.json`.
|
|
108
|
+
1. Gets an `odla_dev_...` token by email-bound device handshake, or reuses
|
|
109
|
+
`ODLA_DEV_TOKEN` / `.odla/dev-token.json`. A fresh handshake requires
|
|
110
|
+
`--email <account>` or `ODLA_USER_EMAIL`; the matching existing account must
|
|
111
|
+
sign in, review the exact code, and approve it. Opening the URL alone does
|
|
112
|
+
not claim the request.
|
|
101
113
|
In an interactive terminal it opens the approval page in your browser when
|
|
102
114
|
the code is displayed. Pass `--open` to force browser launch from a
|
|
103
115
|
non-interactive shell, or `--no-open` to suppress it. Browser launch is
|
|
104
116
|
best-effort; the printed URL and code always remain the fallback.
|
|
105
117
|
2. Creates the platform app if needed.
|
|
106
|
-
3. Enables configured services in every configured environment.
|
|
118
|
+
3. Enables configured services in every configured environment. Calendar
|
|
119
|
+
config is normalized per env and fixed to Google read-only access.
|
|
107
120
|
4. Mints or reuses each env's configured service credentials: an odla-db app
|
|
108
121
|
key for `db` and an ingest token for `o11y`.
|
|
109
122
|
5. Pushes the configured schema and rules.
|
|
110
123
|
6. Configures platform AI and stores provider keys in the tenant vault when the
|
|
111
124
|
configured key env var is set.
|
|
112
|
-
7.
|
|
113
|
-
|
|
125
|
+
7. For calendar, reads owner-visible connection status and, when needed, asks
|
|
126
|
+
the platform for a state-bound Google authorization URL and opens only the
|
|
127
|
+
exact Google OAuth endpoint (or a same-platform interstitial). The human completes consent there;
|
|
128
|
+
provision follows the exact attempt through initial sync. OAuth codes and
|
|
129
|
+
refresh tokens never enter the CLI, repo, 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
|
|
114
132
|
`--push-secrets`, transfers the configured service secrets to the matching
|
|
115
133
|
deployed Worker environment over Wrangler stdin.
|
|
116
134
|
|
|
@@ -127,12 +145,74 @@ The CLI preflights Wrangler first and persists the replacement before pushing;
|
|
|
127
145
|
if that final push still fails, follow the printed `secrets push --env ...`
|
|
128
146
|
retry. Do not run the rotation flag again.
|
|
129
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
|
+
|
|
130
168
|
`smoke` verifies a provisioned environment from local credentials. It fetches
|
|
131
169
|
the platform public config, checks the configured AI provider, fetches the live
|
|
132
170
|
odla-db schema with the tenant key, compares expected schema entities, and runs
|
|
133
171
|
a count aggregate against the first entity. It fails early with a clear message
|
|
134
172
|
when provisioning has not written `.odla/credentials.local.json`.
|
|
135
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 per
|
|
178
|
+
environment, then run normal provision. The first run has two distinct human
|
|
179
|
+
checkpoints: the odla device code establishes app-owner authority, and the
|
|
180
|
+
subsequent server-issued Google page grants `calendar.events.readonly` consent.
|
|
181
|
+
|
|
182
|
+
For parity with a static Google Appointment Schedule embed/link, set the public
|
|
183
|
+
`bookingPageUrl` per environment. Provision applies it through the owner-only
|
|
184
|
+
calendar settings route; it is public configuration, not a credential.
|
|
185
|
+
|
|
186
|
+
`calendar status` returns the safe connection/sync projection; add `--json` for
|
|
187
|
+
agent automation. Once connected, `calendar calendars` lists ids visible to the
|
|
188
|
+
Google identity so the checked-in selection can be refined. `calendar connect`
|
|
189
|
+
applies the checked-in booking-page setting and starts consent when the
|
|
190
|
+
connection is absent, failed, disconnected, or degraded (so an agent can
|
|
191
|
+
repair revoked credentials); a healthy connection is reused. A `needs_sync`
|
|
192
|
+
connection already has provider credentials, so connect/provision resyncs it
|
|
193
|
+
without requesting Google consent again; an existing authorization or initial
|
|
194
|
+
sync is awaited instead of creating a duplicate attempt.
|
|
195
|
+
`calendar resync` asks the hosted connector to sync immediately; `calendar
|
|
196
|
+
disconnect --yes` stops watches and deletes this app/environment connection's
|
|
197
|
+
encrypted platform token and cursors without purging retained mirror rows,
|
|
198
|
+
which may therefore remain readable but stale. It does not revoke the shared
|
|
199
|
+
user-to-Google-OAuth-project grant, because that could invalidate other odla
|
|
200
|
+
connections for the same user. A future explicitly global revoke command would
|
|
201
|
+
need cross-connection accounting and warning. Production resync requires
|
|
202
|
+
`--yes`, as does a direct production connect. None of these commands accepts a
|
|
203
|
+
Google authorization code, client secret, access token, or refresh token.
|
|
204
|
+
|
|
205
|
+
The SDK uses the existing server-side db values (`ODLA_ENDPOINT`,
|
|
206
|
+
`ODLA_TENANT`, `ODLA_API_KEY`), so calendar adds no Worker secret. Never expose
|
|
207
|
+
`ODLA_API_KEY` to a browser. Trusted Worker code can initialize
|
|
208
|
+
`@odla-ai/calendar`; browser code reads `$bookings` through `@odla-ai/db/client`
|
|
209
|
+
under explicit rules or imports pure helpers from `@odla-ai/calendar/client`.
|
|
210
|
+
|
|
211
|
+
These commands operate the current read/embed reconciliation slice. The CLI has
|
|
212
|
+
no native slot-picker or create/reschedule/cancel command, and exposes no
|
|
213
|
+
rolling-window/age-out, quota-backoff, retention/purge, or provider-derived
|
|
214
|
+
mutation-id control. Public health remains aggregate rather than per calendar.
|
|
215
|
+
|
|
136
216
|
The bundled build/migration skills add a passive pre-ship gate with
|
|
137
217
|
`@odla-ai/security`: after the exact-version availability check, run
|
|
138
218
|
`npm i -D --save-exact @odla-ai/security@0.2.2`, then
|
|
@@ -283,7 +363,8 @@ approval), and prod-named envs require `--yes`, matching `secrets push`.
|
|
|
283
363
|
|
|
284
364
|
If a change is deterministic from `odla.config.mjs`, the CLI owns it: app and
|
|
285
365
|
service enablement, credential issuance and local persistence, `.dev.vars`,
|
|
286
|
-
schema/rules/auth/AI configuration,
|
|
366
|
+
schema/rules/auth/AI/calendar configuration, owner-safe consent orchestration,
|
|
367
|
+
and Wrangler secret transfer. The coding
|
|
287
368
|
agent owns application semantics: installing `@odla-ai/o11y`, wrapping the
|
|
288
369
|
Worker with `withObservability`, and choosing useful spans, metrics, errors, and
|
|
289
370
|
LLM-usage records. The human owns the device approval, production consent, and
|
|
@@ -335,7 +416,7 @@ export default {
|
|
|
335
416
|
dbEndpoint: process.env.ODLA_ENDPOINT ?? process.env.ODLA_DB_ENDPOINT ?? "https://db.odla.ai",
|
|
336
417
|
app: { id: "my-app", name: "My App" },
|
|
337
418
|
envs: ["dev"], // add "prod" deliberately; provisioning it requires --yes
|
|
338
|
-
services: ["db", "ai", "o11y"],
|
|
419
|
+
services: ["db", "ai", "o11y", "calendar"],
|
|
339
420
|
db: {
|
|
340
421
|
schema: "./src/odla/schema.mjs",
|
|
341
422
|
rules: "./src/odla/rules.mjs",
|
|
@@ -346,6 +427,21 @@ export default {
|
|
|
346
427
|
provider: process.env.ODLA_AI_PROVIDER ?? "anthropic",
|
|
347
428
|
keyEnv: "ANTHROPIC_API_KEY",
|
|
348
429
|
},
|
|
430
|
+
calendar: {
|
|
431
|
+
google: {
|
|
432
|
+
calendars: { dev: ["primary"] },
|
|
433
|
+
bookingPageUrl: {
|
|
434
|
+
dev: "https://calendar.google.com/calendar/appointments/schedules/…",
|
|
435
|
+
},
|
|
436
|
+
match: {
|
|
437
|
+
summaryPrefix: "Intro", // optional
|
|
438
|
+
organizerSelf: true, // default true
|
|
439
|
+
requireAttendees: true, // default true
|
|
440
|
+
},
|
|
441
|
+
attendeePolicy: "full", // or "hashed"
|
|
442
|
+
// This CLI release always requests calendar.events.readonly.
|
|
443
|
+
},
|
|
444
|
+
},
|
|
349
445
|
auth: {
|
|
350
446
|
// Publishable key (public). Created + pulled by the Clerk CLI (`npx clerk`);
|
|
351
447
|
// See the installed odla-migrate phase 3. Inline `pk_…` or "$ENV_VAR".
|
package/REQUIREMENTS.md
CHANGED
|
@@ -25,11 +25,27 @@ Agnacl, but none should mention or special-case Agnacl.
|
|
|
25
25
|
|
|
26
26
|
- Provisioning must default to device-handshake auth, never a platform admin
|
|
27
27
|
secret in chat or config.
|
|
28
|
-
-
|
|
28
|
+
- A fresh handshake must require the existing account email via `--email` or
|
|
29
|
+
`ODLA_USER_EMAIL`. Email is an identity hint, never a password or bearer
|
|
30
|
+
credential; agents must not request either from the human.
|
|
31
|
+
- Unknown and never-signed-in accounts must not yield a claimable request, but
|
|
32
|
+
the public response must not disclose account existence.
|
|
33
|
+
- The approval code must be printed in a copyable, server-supplied verification
|
|
34
|
+
URL. Opening it must not claim the request; the matching signed-in user must
|
|
35
|
+
explicitly review that exact code before approval controls appear.
|
|
36
|
+
- Only one claimed pending or approved-but-uncollected request may be active per
|
|
37
|
+
user. Unclaimed issued codes must not occupy that slot.
|
|
29
38
|
- Interactive provisioning should launch the browser to the approval page when
|
|
30
39
|
possible. `--open` should force launch; `--no-open` should suppress it.
|
|
31
40
|
- Cached developer tokens must be mode `0600`, gitignored, and reused until
|
|
32
41
|
expiry.
|
|
42
|
+
- Minted developer tokens must have a metadata-only inventory (owner, label,
|
|
43
|
+
scopes, created/expires/last-used/revoked state), immediate owner revocation,
|
|
44
|
+
and global admin incident response. Plaintext is shown only once and never
|
|
45
|
+
returned by inventory.
|
|
46
|
+
- Handshake attempts must retain bounded metadata-only attribution using a
|
|
47
|
+
keyed requester fingerprint rather than a raw IP, with independent issue and
|
|
48
|
+
poll rate limits. Agents and developer tokens must not read this admin trail.
|
|
33
49
|
|
|
34
50
|
## Safe Provisioning
|
|
35
51
|
|
|
@@ -44,6 +60,20 @@ Agnacl, but none should mention or special-case Agnacl.
|
|
|
44
60
|
configured custom in-repository paths, must be mode `0600` where applicable
|
|
45
61
|
and gitignored.
|
|
46
62
|
- O11y-only projects must not create or require an odla-db key.
|
|
63
|
+
- Calendar projects must require db, apply one normalized config per env, and
|
|
64
|
+
use the existing db app key rather than introducing an application-held
|
|
65
|
+
Google credential.
|
|
66
|
+
- Google consent must be a separate, state-bound platform checkpoint. The CLI may
|
|
67
|
+
print/open and poll an opaque attempt, but must never receive an OAuth code,
|
|
68
|
+
access token, or refresh token.
|
|
69
|
+
- Read-only calendar intent must request only
|
|
70
|
+
`calendar.events.readonly`; scope elevation belongs in a later explicit flow.
|
|
71
|
+
- Calendar connect/status/discovery/resync/disconnect must be resumable and
|
|
72
|
+
machine-readable. Disconnect must be explicit and disclose that retained
|
|
73
|
+
mirror rows can remain stale.
|
|
74
|
+
- A public per-env `bookingPageUrl` must be validated and applied independently
|
|
75
|
+
of connector config so static Appointment Schedule embeds need no Google/app
|
|
76
|
+
credential in browser code.
|
|
47
77
|
- Schema pushes must be explicit and visible in dry-run.
|
|
48
78
|
- If rules are omitted, schema-derived deny-all rules are the safe default.
|
|
49
79
|
|