@odla-ai/cli 0.8.0 → 0.10.0

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 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,8 +29,8 @@ 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.8.0 version
33
- npm i -D --save-exact @odla-ai/cli@0.8.0
32
+ npm view @odla-ai/cli@0.10.0 version
33
+ npm i -D --save-exact @odla-ai/cli@0.10.0
34
34
  ```
35
35
 
36
36
  ## Prerequisites
@@ -53,12 +53,19 @@ npm i -D --save-exact @odla-ai/cli@0.8.0
53
53
  npx odla-ai setup
54
54
  npx odla-ai init --app-id my-app --name "My App"
55
55
  npx odla-ai doctor
56
+ npx odla-ai calendar status --env dev
57
+ npx odla-ai calendar calendars --env dev
58
+ npx odla-ai calendar connect --env dev
59
+ npx odla-ai calendar resync --env dev
60
+ npx odla-ai calendar disconnect --env dev --yes
56
61
  npx odla-ai capabilities --json
57
62
  # install SDKs, write the Worker, and create wrangler.jsonc before secret push
58
63
  npx odla-ai provision --dry-run
59
64
  npx odla-ai provision --write-dev-vars --push-secrets
60
65
  npx odla-ai smoke --env dev
61
66
  npx odla-ai secrets push --env dev
67
+ npx odla-ai secrets set clerk_webhook_secret --env dev --stdin
68
+ npx odla-ai secrets set-clerk-key --env dev --from-env CLERK_SECRET_KEY
62
69
  npx odla-ai security run . --env dev --ack-redacted-source
63
70
  npx odla-ai security github connect --env dev # infers owner/name from git origin
64
71
  npx odla-ai security plan --env dev
@@ -101,14 +108,20 @@ shown-once credential.
101
108
  non-interactive shell, or `--no-open` to suppress it. Browser launch is
102
109
  best-effort; the printed URL and code always remain the fallback.
103
110
  2. Creates the platform app if needed.
104
- 3. Enables configured services in every configured environment.
111
+ 3. Enables configured services in every configured environment. Calendar
112
+ config is normalized per env and fixed to Google read-only access.
105
113
  4. Mints or reuses each env's configured service credentials: an odla-db app
106
114
  key for `db` and an ingest token for `o11y`.
107
115
  5. Pushes the configured schema and rules.
108
116
  6. Configures platform AI and stores provider keys in the tenant vault when the
109
117
  configured key env var is set.
110
- 7. Writes `.odla/credentials.local.json` with mode `0600`.
111
- 8. With `--write-dev-vars`, writes the local Worker values to `.dev.vars`; with
118
+ 7. For calendar, reads owner-visible connection status and, when needed, asks
119
+ the platform for a state-bound Google authorization URL and opens only the
120
+ exact Google OAuth endpoint (or a same-platform interstitial). The human completes consent there;
121
+ provision follows the exact attempt through initial sync. OAuth codes and
122
+ refresh tokens never enter the CLI, repo, chat, or app.
123
+ 8. Writes `.odla/credentials.local.json` with mode `0600`.
124
+ 9. With `--write-dev-vars`, writes the local Worker values to `.dev.vars`; with
112
125
  `--push-secrets`, transfers the configured service secrets to the matching
113
126
  deployed Worker environment over Wrangler stdin.
114
127
 
@@ -131,6 +144,48 @@ odla-db schema with the tenant key, compares expected schema entities, and runs
131
144
  a count aggregate against the first entity. It fails early with a clear message
132
145
  when provisioning has not written `.odla/credentials.local.json`.
133
146
 
147
+ ### Read-only Google Calendar
148
+
149
+ Calendar is a platform-custodied connector, not a Google credential stored by
150
+ the application. Enable both `db` and `calendar`, configure calendar ids per
151
+ environment, then run normal provision. The first run has two distinct human
152
+ checkpoints: the odla device code establishes app-owner authority, and the
153
+ subsequent server-issued Google page grants `calendar.events.readonly` consent.
154
+
155
+ For parity with a static Google Appointment Schedule embed/link, set the public
156
+ `bookingPageUrl` per environment. Provision applies it through the owner-only
157
+ calendar settings route; it is public configuration, not a credential.
158
+
159
+ `calendar status` returns the safe connection/sync projection; add `--json` for
160
+ agent automation. Once connected, `calendar calendars` lists ids visible to the
161
+ Google identity so the checked-in selection can be refined. `calendar connect`
162
+ applies the checked-in booking-page setting and starts consent when the
163
+ connection is absent, failed, disconnected, or degraded (so an agent can
164
+ repair revoked credentials); a healthy connection is reused. A `needs_sync`
165
+ connection already has provider credentials, so connect/provision resyncs it
166
+ without requesting Google consent again; an existing authorization or initial
167
+ sync is awaited instead of creating a duplicate attempt.
168
+ `calendar resync` asks the hosted connector to sync immediately; `calendar
169
+ disconnect --yes` stops watches and deletes this app/environment connection's
170
+ encrypted platform token and cursors without purging retained mirror rows,
171
+ which may therefore remain readable but stale. It does not revoke the shared
172
+ user-to-Google-OAuth-project grant, because that could invalidate other odla
173
+ connections for the same user. A future explicitly global revoke command would
174
+ need cross-connection accounting and warning. Production resync requires
175
+ `--yes`, as does a direct production connect. None of these commands accepts a
176
+ Google authorization code, client secret, access token, or refresh token.
177
+
178
+ The SDK uses the existing server-side db values (`ODLA_ENDPOINT`,
179
+ `ODLA_TENANT`, `ODLA_API_KEY`), so calendar adds no Worker secret. Never expose
180
+ `ODLA_API_KEY` to a browser. Trusted Worker code can initialize
181
+ `@odla-ai/calendar`; browser code reads `$bookings` through `@odla-ai/db/client`
182
+ under explicit rules or imports pure helpers from `@odla-ai/calendar/client`.
183
+
184
+ These commands operate the current read/embed reconciliation slice. The CLI has
185
+ no native slot-picker or create/reschedule/cancel command, and exposes no
186
+ rolling-window/age-out, quota-backoff, retention/purge, or provider-derived
187
+ mutation-id control. Public health remains aggregate rather than per calendar.
188
+
134
189
  The bundled build/migration skills add a passive pre-ship gate with
135
190
  `@odla-ai/security`: after the exact-version availability check, run
136
191
  `npm i -D --save-exact @odla-ai/security@0.2.2`, then
@@ -261,11 +316,28 @@ redacted plan without spawning anything. For the normal path, use
261
316
  `provision --write-dev-vars --push-secrets` so service enablement, credential
262
317
  issuance, local config, and deployed secret transfer stay one composition.
263
318
 
319
+ `secrets set <name> --env <env>` stores one named secret in that env's tenant
320
+ vault — the same write-only slot Studio's Secrets panel fills (for example
321
+ `clerk_webhook_secret` for synced auth). The value may come only from
322
+ `--from-env <NAME>` or `--stdin`, so a producer command pipes straight into the
323
+ vault without the secret ever appearing on argv, in output, or in an agent's
324
+ transcript; it is encrypted at rest and readable back only by that tenant's
325
+ app API key, never by the CLI, Studio, or the developer token. `$`-prefixed
326
+ names are platform-reserved. `secrets set-clerk-key --env <env>` stores the
327
+ app's Clerk secret key in the reserved `$clerk_secret` slot so the platform can
328
+ resolve the app's users (invites, member lookups); reserved secrets are never
329
+ readable by app keys. It refuses an `sk_test_` key for a prod-named env and
330
+ requires `--yes` to put an `sk_live_` key into a non-prod env, since live users
331
+ would sync into a non-prod tenant. Both commands authenticate with the
332
+ developer token (`$ODLA_DEV_TOKEN`, the cached token, or a fresh device
333
+ approval), and prod-named envs require `--yes`, matching `secrets push`.
334
+
264
335
  ## Who does what
265
336
 
266
337
  If a change is deterministic from `odla.config.mjs`, the CLI owns it: app and
267
338
  service enablement, credential issuance and local persistence, `.dev.vars`,
268
- schema/rules/auth/AI configuration, and Wrangler secret transfer. The coding
339
+ schema/rules/auth/AI/calendar configuration, owner-safe consent orchestration,
340
+ and Wrangler secret transfer. The coding
269
341
  agent owns application semantics: installing `@odla-ai/o11y`, wrapping the
270
342
  Worker with `withObservability`, and choosing useful spans, metrics, errors, and
271
343
  LLM-usage records. The human owns the device approval, production consent, and
@@ -317,7 +389,7 @@ export default {
317
389
  dbEndpoint: process.env.ODLA_ENDPOINT ?? process.env.ODLA_DB_ENDPOINT ?? "https://db.odla.ai",
318
390
  app: { id: "my-app", name: "My App" },
319
391
  envs: ["dev"], // add "prod" deliberately; provisioning it requires --yes
320
- services: ["db", "ai", "o11y"],
392
+ services: ["db", "ai", "o11y", "calendar"],
321
393
  db: {
322
394
  schema: "./src/odla/schema.mjs",
323
395
  rules: "./src/odla/rules.mjs",
@@ -328,6 +400,21 @@ export default {
328
400
  provider: process.env.ODLA_AI_PROVIDER ?? "anthropic",
329
401
  keyEnv: "ANTHROPIC_API_KEY",
330
402
  },
403
+ calendar: {
404
+ google: {
405
+ calendars: { dev: ["primary"] },
406
+ bookingPageUrl: {
407
+ dev: "https://calendar.google.com/calendar/appointments/schedules/…",
408
+ },
409
+ match: {
410
+ summaryPrefix: "Intro", // optional
411
+ organizerSelf: true, // default true
412
+ requireAttendees: true, // default true
413
+ },
414
+ attendeePolicy: "full", // or "hashed"
415
+ // This CLI release always requests calendar.events.readonly.
416
+ },
417
+ },
331
418
  auth: {
332
419
  // Publishable key (public). Created + pulled by the Clerk CLI (`npx clerk`);
333
420
  // See the installed odla-migrate phase 3. Inline `pk_…` or "$ENV_VAR".
package/REQUIREMENTS.md CHANGED
@@ -44,6 +44,20 @@ Agnacl, but none should mention or special-case Agnacl.
44
44
  configured custom in-repository paths, must be mode `0600` where applicable
45
45
  and gitignored.
46
46
  - O11y-only projects must not create or require an odla-db key.
47
+ - Calendar projects must require db, apply one normalized config per env, and
48
+ use the existing db app key rather than introducing an application-held
49
+ Google credential.
50
+ - Google consent must be a separate, state-bound platform checkpoint. The CLI may
51
+ print/open and poll an opaque attempt, but must never receive an OAuth code,
52
+ access token, or refresh token.
53
+ - Read-only calendar intent must request only
54
+ `calendar.events.readonly`; scope elevation belongs in a later explicit flow.
55
+ - Calendar connect/status/discovery/resync/disconnect must be resumable and
56
+ machine-readable. Disconnect must be explicit and disclose that retained
57
+ mirror rows can remain stale.
58
+ - A public per-env `bookingPageUrl` must be validated and applied independently
59
+ of connector config so static Appointment Schedule embeds need no Google/app
60
+ credential in browser code.
47
61
  - Schema pushes must be explicit and visible in dry-run.
48
62
  - If rules are omitted, schema-derived deny-all rules are the safe default.
49
63