@odla-ai/cli 0.10.0 → 0.10.2
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 +35 -8
- package/REQUIREMENTS.md +20 -2
- 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/package.json +7 -9
- package/skills/odla/SKILL.md +11 -4
- package/skills/odla/references/build.md +11 -8
- package/skills/odla/references/sdks.md +6 -5
- package/skills/odla-migrate/SKILL.md +6 -2
- package/skills/odla-migrate/references/phase-2-db.md +12 -9
- package/skills/odla-migrate/references/phase-2b-calendar.md +2 -2
- package/skills/odla-migrate/references/phase-4-ai.md +4 -3
- package/skills/odla-migrate/references/phase-5-cutover.md +2 -2
- package/skills/odla-migrate/references/secrets-map.md +2 -1
- package/skills/odla-migrate/references/troubleshooting.md +6 -4
- package/skills/odla-o11y-debug/SKILL.md +7 -3
- package/dist/chunk-WDKBW4BE.js.map +0 -1
- package/llms.txt +0 -1221
package/llms.txt
DELETED
|
@@ -1,1221 +0,0 @@
|
|
|
1
|
-
# @odla-ai/cli — LLM context
|
|
2
|
-
|
|
3
|
-
> Agent-operable CLI for odla provisioning, calendar consent and sync lifecycle, System AI administration, Worker secrets, security jobs, and smoke checks.
|
|
4
|
-
|
|
5
|
-
> ⚠️ **Early access — pre-1.0.** Agents work from bounded runbooks; humans
|
|
6
|
-
> approve credentials, production changes, releases, and merges. APIs and exact
|
|
7
|
-
> package availability can change. Review the documented guarantees and
|
|
8
|
-
> limitations; this software is MIT-licensed and provided without warranty.
|
|
9
|
-
|
|
10
|
-
Project-neutral provisioning CLI for odla apps. It creates and validates an
|
|
11
|
-
`odla.config.mjs`, then uses that config to register an app, enable services,
|
|
12
|
-
push odla-db schema/rules, configure per-app BYOK AI, configure Clerk auth, record
|
|
13
|
-
deployment links, connect read-only Google Calendar mirrors, provision o11y ingest credentials, and transfer local or
|
|
14
|
-
deployed Worker secrets without printing them. It also gives platform admins a
|
|
15
|
-
scoped System AI control surface and gives app owners a provider-key-free
|
|
16
|
-
hosted security command.
|
|
17
|
-
|
|
18
|
-
It does not know about any specific app. App identity, environments, services,
|
|
19
|
-
schema, rules, auth, AI provider, and links all come from config.
|
|
20
|
-
|
|
21
|
-
## Install
|
|
22
|
-
|
|
23
|
-
No install needed — the package ships a single `odla-ai` binary, so npx can run
|
|
24
|
-
it directly:
|
|
25
|
-
|
|
26
|
-
```bash
|
|
27
|
-
npx @odla-ai/cli init --app-id my-app --name "My App"
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
For a project you keep working in, install it as a dev dependency so the
|
|
31
|
-
shorter `npx odla-ai` form works and the version is pinned by your lockfile:
|
|
32
|
-
|
|
33
|
-
```bash
|
|
34
|
-
npm view @odla-ai/cli@0.10.0 version
|
|
35
|
-
npm i -D --save-exact @odla-ai/cli@0.10.0
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
## Prerequisites
|
|
39
|
-
|
|
40
|
-
- Node.js 20 or newer (`node --version`).
|
|
41
|
-
- odla apps usually deploy as Cloudflare Workers. If you have never used
|
|
42
|
-
Cloudflare:
|
|
43
|
-
1. Create a free account at <https://dash.cloudflare.com/sign-up>.
|
|
44
|
-
2. You do not need to install anything: `npx wrangler login` opens the
|
|
45
|
-
browser once to link your account, `npx wrangler dev` runs a Worker
|
|
46
|
-
locally, and `npx wrangler deploy` ships it.
|
|
47
|
-
3. The `.dev.vars` file this CLI writes with `provision --write-dev-vars` is
|
|
48
|
-
wrangler's local secrets file — `wrangler dev` picks it up automatically.
|
|
49
|
-
It is chmod `0600` and gitignored; never commit it or paste its contents
|
|
50
|
-
into `wrangler.toml`.
|
|
51
|
-
|
|
52
|
-
## Commands
|
|
53
|
-
|
|
54
|
-
```bash
|
|
55
|
-
npx odla-ai setup
|
|
56
|
-
npx odla-ai init --app-id my-app --name "My App"
|
|
57
|
-
npx odla-ai doctor
|
|
58
|
-
npx odla-ai calendar status --env dev
|
|
59
|
-
npx odla-ai calendar calendars --env dev
|
|
60
|
-
npx odla-ai calendar connect --env dev
|
|
61
|
-
npx odla-ai calendar resync --env dev
|
|
62
|
-
npx odla-ai calendar disconnect --env dev --yes
|
|
63
|
-
npx odla-ai capabilities --json
|
|
64
|
-
# install SDKs, write the Worker, and create wrangler.jsonc before secret push
|
|
65
|
-
npx odla-ai provision --dry-run
|
|
66
|
-
npx odla-ai provision --write-dev-vars --push-secrets
|
|
67
|
-
npx odla-ai smoke --env dev
|
|
68
|
-
npx odla-ai secrets push --env dev
|
|
69
|
-
npx odla-ai secrets set clerk_webhook_secret --env dev --stdin
|
|
70
|
-
npx odla-ai secrets set-clerk-key --env dev --from-env CLERK_SECRET_KEY
|
|
71
|
-
npx @odla-ai/cli security run . --env dev --ack-redacted-source
|
|
72
|
-
npx @odla-ai/cli security github connect --env dev # infers owner/name from git origin
|
|
73
|
-
npx @odla-ai/cli security plan --env dev
|
|
74
|
-
npx @odla-ai/cli security sources --env dev
|
|
75
|
-
npx @odla-ai/cli security run --source <source-id> --ref main --env dev --plan-digest <digest-from-security-plan> --ack-redacted-source
|
|
76
|
-
npx @odla-ai/cli security status <job-id>
|
|
77
|
-
npx @odla-ai/cli security report <job-id>
|
|
78
|
-
npx odla-ai admin ai show
|
|
79
|
-
npx odla-ai admin ai models
|
|
80
|
-
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
|
|
81
|
-
npx odla-ai admin ai credentials
|
|
82
|
-
npx odla-ai admin ai credential set anthropic --from-env ANTHROPIC_API_KEY
|
|
83
|
-
npx odla-ai admin ai usage --app-id my-app --env prod --limit 50
|
|
84
|
-
npx odla-ai admin ai audit --limit 25
|
|
85
|
-
npx odla-ai skill install
|
|
86
|
-
npx odla-ai version
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
`init` writes:
|
|
90
|
-
|
|
91
|
-
- `odla.config.mjs`
|
|
92
|
-
- `src/odla/schema.mjs`
|
|
93
|
-
- `src/odla/rules.mjs`
|
|
94
|
-
- `.gitignore` entries for local credentials
|
|
95
|
-
|
|
96
|
-
New configs contain only the `dev` environment. Add `prod` explicitly after
|
|
97
|
-
the development flow is healthy; `provision` refuses to mutate `prod` or
|
|
98
|
-
`production` without `--yes` and supports `--dry-run` for review.
|
|
99
|
-
|
|
100
|
-
`provision` performs the standard safe setup flow:
|
|
101
|
-
|
|
102
|
-
When using `--push-secrets`, create the Worker and its Wrangler config first.
|
|
103
|
-
The CLI checks that config and `wrangler whoami` before it issues or rotates a
|
|
104
|
-
shown-once credential.
|
|
105
|
-
|
|
106
|
-
1. Gets an `odla_dev_...` token by device handshake, or reuses
|
|
107
|
-
`ODLA_DEV_TOKEN` / `.odla/dev-token.json`.
|
|
108
|
-
In an interactive terminal it opens the approval page in your browser when
|
|
109
|
-
the code is displayed. Pass `--open` to force browser launch from a
|
|
110
|
-
non-interactive shell, or `--no-open` to suppress it. Browser launch is
|
|
111
|
-
best-effort; the printed URL and code always remain the fallback.
|
|
112
|
-
2. Creates the platform app if needed.
|
|
113
|
-
3. Enables configured services in every configured environment. Calendar
|
|
114
|
-
intent is normalized per env and fixed to Google read-only access.
|
|
115
|
-
4. Mints or reuses each env's configured service credentials: an odla-db app
|
|
116
|
-
key for `db` and an ingest token for `o11y`.
|
|
117
|
-
5. Pushes the configured schema and rules.
|
|
118
|
-
6. Configures platform AI and stores provider keys in the tenant vault when the
|
|
119
|
-
configured key env var is set.
|
|
120
|
-
7. With calendar enabled, starts a separate state-bound Google consent attempt
|
|
121
|
-
when needed and follows it through initial sync. The human completes OAuth;
|
|
122
|
-
codes and tokens never enter the CLI, repository, 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
|
|
125
|
-
`--push-secrets`, transfers the configured service secrets to the matching
|
|
126
|
-
deployed Worker environment over Wrangler stdin.
|
|
127
|
-
|
|
128
|
-
Plain reruns are idempotent. Pass `--rotate-o11y-token` only when deliberately
|
|
129
|
-
invalidating and replacing the o11y token; combine it with `--push-secrets` so
|
|
130
|
-
the replacement reaches the Worker in the same run. `--rotate-keys` remains the
|
|
131
|
-
broader credential rotation. Production mutation or secret transfer requires
|
|
132
|
-
`--yes`. Pass `--no-write-credentials` to skip writing the local credentials
|
|
133
|
-
file; it cannot be combined with an operation that would issue a shown-once
|
|
134
|
-
credential.
|
|
135
|
-
|
|
136
|
-
Rotation and Wrangler secret replacement are not a distributed transaction.
|
|
137
|
-
The CLI preflights Wrangler first and persists the replacement before pushing;
|
|
138
|
-
if that final push still fails, follow the printed `secrets push --env ...`
|
|
139
|
-
retry. Do not run the rotation flag again.
|
|
140
|
-
|
|
141
|
-
`smoke` verifies a provisioned environment from local credentials. It fetches
|
|
142
|
-
the platform public config, checks the configured AI provider, fetches the live
|
|
143
|
-
odla-db schema with the tenant key, compares expected schema entities, and runs
|
|
144
|
-
a count aggregate against the first entity. It fails early with a clear message
|
|
145
|
-
when provisioning has not written `.odla/credentials.local.json`.
|
|
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 and an
|
|
151
|
-
optional public Appointment Schedule `bookingPageUrl` per environment, then run
|
|
152
|
-
normal provision. The first run has two human checkpoints: the odla device code
|
|
153
|
-
establishes app-owner authority, then Google grants read-only Calendar scopes.
|
|
154
|
-
|
|
155
|
-
`calendar status --json` returns the safe connection/sync projection.
|
|
156
|
-
`calendar calendars --json` lists ids visible after consent; update checked-in
|
|
157
|
-
config and re-provision. A resulting `needs_sync` state reuses the installed
|
|
158
|
-
provider credential and resyncs without another OAuth attempt; an existing
|
|
159
|
-
authorization or initial sync is awaited rather than duplicated. `calendar
|
|
160
|
-
resync` requests an immediate sync, while
|
|
161
|
-
`calendar disconnect --yes` stops watches and deletes this app/environment
|
|
162
|
-
connection's encrypted platform token and cursors without purging retained
|
|
163
|
-
mirror rows, which therefore become stale. It does not revoke the shared
|
|
164
|
-
user-to-Google-OAuth-project grant, because that could invalidate other odla
|
|
165
|
-
connections for the same user. A future explicitly global revoke command would
|
|
166
|
-
need cross-connection accounting and warning. Production resync requires the
|
|
167
|
-
CLI's explicit `--yes` checkpoint, and disconnect always requires it. None of
|
|
168
|
-
these commands accepts a Google code, client secret, access token, or refresh
|
|
169
|
-
token.
|
|
170
|
-
|
|
171
|
-
The application uses its existing server-side `ODLA_ENDPOINT`, `ODLA_TENANT`,
|
|
172
|
-
and `ODLA_API_KEY`; calendar adds no app Worker secret. Never expose the app key
|
|
173
|
-
to a browser. Provider write actions are outside this read-only slice.
|
|
174
|
-
|
|
175
|
-
These commands operate the current read/embed reconciliation slice. The CLI has
|
|
176
|
-
no native slot-picker or create/reschedule/cancel command, and exposes no
|
|
177
|
-
rolling-window/age-out, quota-backoff, retention/purge, or provider-derived
|
|
178
|
-
mutation-id control. Public health remains aggregate rather than per calendar.
|
|
179
|
-
|
|
180
|
-
The bundled build/migration skills add a passive pre-ship gate with
|
|
181
|
-
`@odla-ai/security`: after the exact-version availability check, run
|
|
182
|
-
`npm i -D --save-exact @odla-ai/security@0.2.2`, then
|
|
183
|
-
`npx odla-security scan . --profile odla --out .odla/security/pre-ship --fail-on high --fail-on-candidates critical`.
|
|
184
|
-
The passive scan remains a separate binary: it makes no model calls and does
|
|
185
|
-
not execute target code. After explicit redacted-source approval,
|
|
186
|
-
`odla-ai security run . --env dev --ack-redacted-source` adds hosted discovery
|
|
187
|
-
and independent validation. The CLI obtains/reuses app-owner auth and the
|
|
188
|
-
platform supplies bounded role grants; it never requests provider keys.
|
|
189
|
-
The CLI schedules within those grants: recon consumes one discovery call,
|
|
190
|
-
first-pass hunts are capped before retries, and validation handles the
|
|
191
|
-
highest-risk candidates first. Used/skipped role calls appear in the summary
|
|
192
|
-
and report. Budget-limited coverage is explicitly incomplete and still fails
|
|
193
|
-
the default gate unless `--allow-incomplete` is supplied after review.
|
|
194
|
-
All hosted-security network calls target the configured odla platform origin.
|
|
195
|
-
The CLI transmits typed redacted security operations only and never contacts a
|
|
196
|
-
model-provider host; odla.ai owns the prompts/schemas, route, credential,
|
|
197
|
-
provider call, attribution, and receipt. Cached/environment tokens are bound to
|
|
198
|
-
their canonical platform audience and are rejected before disclosure on a
|
|
199
|
-
different origin. For a non-default platform, set the matching
|
|
200
|
-
`ODLA_DEV_TOKEN_AUDIENCE` with `ODLA_DEV_TOKEN`.
|
|
201
|
-
Early-access run ceilings are rolling. A platform-ceiling `429` always carries
|
|
202
|
-
a conservative `Retry-After`. A provider-side `429` uses the sanitized
|
|
203
|
-
`provider_rate_limited` code after the provider SDK's bounded retries and
|
|
204
|
-
carries a bounded `Retry-After` only when the upstream supplied one. The CLI
|
|
205
|
-
does not echo arbitrary response text or silently change the admin-selected
|
|
206
|
-
model.
|
|
207
|
-
Before installing the exact release, require
|
|
208
|
-
`npm view @odla-ai/security@0.2.2 version` to succeed before installation. An
|
|
209
|
-
exact-version `E404` means the release is unavailable, not that the security
|
|
210
|
-
preflight passed, and does not prove the package name is absent. odla's own
|
|
211
|
-
engineering environment uses an equivalent internal gate; customer projects
|
|
212
|
-
should use the published `odla-security` command above.
|
|
213
|
-
|
|
214
|
-
For a server-side, commit-pinned review, connect one repository through odla's
|
|
215
|
-
GitHub App. Contents and Metadata access are read-only; optional Checks write
|
|
216
|
-
access publishes only a best-effort summary. The CLI infers `owner/name` from a
|
|
217
|
-
safe GitHub HTTPS or SSH `origin`; pass `--repo owner/name` when it cannot. It
|
|
218
|
-
opens GitHub's installation/authorization page and polls that exact odla
|
|
219
|
-
attempt. Finish each browser stage within its displayed 15-minute window:
|
|
220
|
-
|
|
221
|
-
```bash
|
|
222
|
-
npx @odla-ai/cli security github connect --env dev
|
|
223
|
-
npx @odla-ai/cli security plan --env dev
|
|
224
|
-
npx @odla-ai/cli security sources --env dev
|
|
225
|
-
npx @odla-ai/cli security run --source <source-id> --ref main --env dev --plan-digest <digest-from-security-plan> --ack-redacted-source
|
|
226
|
-
```
|
|
227
|
-
|
|
228
|
-
The source job follows by default, renders the normalized report, and applies
|
|
229
|
-
the same confirmed/candidate/incomplete gates; `--no-follow` only enqueues.
|
|
230
|
-
`security status` and `security report` inspect prior jobs, while `security
|
|
231
|
-
github disconnect --source <source-id> --env dev --yes` revokes the saved
|
|
232
|
-
source without requiring a GitHub-side uninstall. A source id belongs to one
|
|
233
|
-
app/environment; reconnect separately for another environment. Disconnect
|
|
234
|
-
cancels nonterminal work, while terminal reports remain until normal expiry.
|
|
235
|
-
The App is not subscribed to Push; an unexpectedly delivered Push event is
|
|
236
|
-
ignored and never starts a job. Source jobs default to `cloudflare-app`;
|
|
237
|
-
local-path jobs default to `odla`.
|
|
238
|
-
|
|
239
|
-
Clients send only an opaque odla source id, ref, profile, and explicit redacted
|
|
240
|
-
disclosure acknowledgement—never a PAT, installation id, provider key, or
|
|
241
|
-
provider/model selection override. The CLI deliberately displays the read-only
|
|
242
|
-
route identities in the consent preflight. odla.ai verifies access, pins the ref to a commit SHA,
|
|
243
|
-
fetches the bounded snapshot server-side, and uses the admin-selected System AI
|
|
244
|
-
routes. `security plan` shows both provider/model routes, exact policy
|
|
245
|
-
revisions and bounds, prompt/redaction/report contracts, readiness, retention,
|
|
246
|
-
and the no-execution boundary before consent. Each job requires
|
|
247
|
-
`--plan-digest` and binds acknowledgement to that complete digest; any covered
|
|
248
|
-
change requires a refreshed plan and acknowledgement.
|
|
249
|
-
|
|
250
|
-
After validating that plan digest, the CLI fetches and prints the atomic
|
|
251
|
-
server-authored execution intent for the exact app/environment, opaque source,
|
|
252
|
-
ref (or default branch), profile, redacted disclosure, and plan digest. Its
|
|
253
|
-
`executionDigest` is persisted with the job and sent back as
|
|
254
|
-
`expectedExecutionDigest`; a changed selection fails with `intent_conflict`
|
|
255
|
-
instead of running under generic consent. Repository display text is not digest
|
|
256
|
-
authority.
|
|
257
|
-
An omitted `--ref` is canonicalized to the source's current default-branch name
|
|
258
|
-
during preview. A branch-default change before enqueue invalidates the intent
|
|
259
|
-
instead of changing what the Workflow will acquire.
|
|
260
|
-
|
|
261
|
-
GitHub read access is not disclosure consent. No raw archive, file body, or
|
|
262
|
-
explicit source excerpt is deliberately persisted in the hosted report or
|
|
263
|
-
Workflow checkpoints. The private report may keep bounded,
|
|
264
|
-
best-effort credential-pattern-redacted model-derived prose and repository-relative paths for up to
|
|
265
|
-
90 days; treat it as sensitive because it may reveal source semantics.
|
|
266
|
-
Provider/GitHub terms are separate.
|
|
267
|
-
|
|
268
|
-
The archive envelope is 16 MiB compressed, 48 MiB decompressed, 20,000 entries,
|
|
269
|
-
10,000 files, 2 MiB per file, and 16 MiB aggregate file bytes. Links, special
|
|
270
|
-
entries, unsafe redirects, duplicate paths, and escaping paths are rejected.
|
|
271
|
-
The combined acquire/analyze step has zero automatic retries; after a terminal
|
|
272
|
-
failure, correct the ref/access/archive shape or wait for service recovery and
|
|
273
|
-
explicitly start a new job.
|
|
274
|
-
|
|
275
|
-
Checks are optional, best-effort summaries, use fixed conclusion semantics, and
|
|
276
|
-
are not the configurable CLI gate. Target code is not executed. Without an
|
|
277
|
-
injected isolated executor, hosted inference cannot mechanically confirm a
|
|
278
|
-
finding; critical candidates and incomplete coverage remain the operative
|
|
279
|
-
gates, and a clean result is not proof of security.
|
|
280
|
-
|
|
281
|
-
`admin ai show|models|set|credentials|credential set|usage|audit` manages platform-funded System
|
|
282
|
-
AI (`o11y.triage`, `security.discovery`, `security.validation`). It uses a
|
|
283
|
-
separate, mode-`0600` `.odla/admin-token.local.json` cache. Studio displays the
|
|
284
|
-
exact scope, only an admin can approve it, and it expires after ~15 minutes;
|
|
285
|
-
policy, credential, and usage capabilities are separate and cannot act as the
|
|
286
|
-
approver on ordinary app/db/o11y routes. `admin ai models` reads the server
|
|
287
|
-
catalog. `admin ai set security` updates discovery and independent validation
|
|
288
|
-
together with expected revisions; a concurrent edit returns 409 and reloads
|
|
289
|
-
instead of being overwritten. `admin ai usage` requests its own read-only
|
|
290
|
-
capability and lists metadata-only events and status aggregates; filter by
|
|
291
|
-
`--app-id`, `--env`, `--run-id`, and `--limit`, or emit `--json`. Prompts,
|
|
292
|
-
repository source, model output, reports, and provider credentials are never in
|
|
293
|
-
that response.
|
|
294
|
-
`admin ai audit` uses its own read capability for immutable, metadata-only
|
|
295
|
-
policy and credential change events with actor attribution; credential values
|
|
296
|
-
never enter that trail. Credential writes accept only
|
|
297
|
-
`--from-env <NAME>` or `--stdin` and never place the value in argv, output, or
|
|
298
|
-
the cache. System AI and each app's BYOK AI are separate vault/funding paths.
|
|
299
|
-
Admin bounds can only narrow hard ceilings of 64 calls per role/run and, for
|
|
300
|
-
each call, 512 KiB input and 32,768 output tokens. A non-default platform environment token
|
|
301
|
-
must declare the matching `ODLA_ADMIN_TOKEN_AUDIENCE`.
|
|
302
|
-
|
|
303
|
-
`secrets push --env <env>` is the narrower recovery/retry command. It moves the
|
|
304
|
-
configured env's odla-db key and/or o11y ingest token from
|
|
305
|
-
`.odla/credentials.local.json` into the deployed Worker by piping each value
|
|
306
|
-
over stdin to `wrangler secret put`; values never appear on argv, in output, or
|
|
307
|
-
in an agent's transcript. It preflights `wrangler whoami` and the presence of a
|
|
308
|
-
wrangler config file. The env `prod`/`production` targets the top-level
|
|
309
|
-
wrangler environment (no `--env` flag is passed to Wrangler) and requires
|
|
310
|
-
`--yes`; every other env maps to `wrangler --env <name>`. `--dry-run` prints a
|
|
311
|
-
redacted plan without spawning anything. For the normal path, use
|
|
312
|
-
`provision --write-dev-vars --push-secrets` so service enablement, credential
|
|
313
|
-
issuance, local config, and deployed secret transfer stay one composition.
|
|
314
|
-
|
|
315
|
-
`secrets set <name> --env <env>` stores one named secret in that env's tenant
|
|
316
|
-
vault — the same write-only slot Studio's Secrets panel fills (for example
|
|
317
|
-
`clerk_webhook_secret` for synced auth). The value may come only from
|
|
318
|
-
`--from-env <NAME>` or `--stdin`, so a producer command pipes straight into the
|
|
319
|
-
vault without the secret ever appearing on argv, in output, or in an agent's
|
|
320
|
-
transcript; it is encrypted at rest and readable back only by that tenant's
|
|
321
|
-
app API key, never by the CLI, Studio, or the developer token. `$`-prefixed
|
|
322
|
-
names are platform-reserved. `secrets set-clerk-key --env <env>` stores the
|
|
323
|
-
app's Clerk secret key in the reserved `$clerk_secret` slot so the platform can
|
|
324
|
-
resolve the app's users (invites, member lookups); reserved secrets are never
|
|
325
|
-
readable by app keys. It refuses an `sk_test_` key for a prod-named env and
|
|
326
|
-
requires `--yes` to put an `sk_live_` key into a non-prod env, since live users
|
|
327
|
-
would sync into a non-prod tenant. Both commands authenticate with the
|
|
328
|
-
developer token (`$ODLA_DEV_TOKEN`, the cached token, or a fresh device
|
|
329
|
-
approval), and prod-named envs require `--yes`, matching `secrets push`.
|
|
330
|
-
|
|
331
|
-
## Who does what
|
|
332
|
-
|
|
333
|
-
If a change is deterministic from `odla.config.mjs`, the CLI owns it: app and
|
|
334
|
-
service enablement, credential issuance and local persistence, `.dev.vars`,
|
|
335
|
-
schema/rules/auth/AI configuration, and Wrangler secret transfer. The coding
|
|
336
|
-
agent owns application semantics: installing `@odla-ai/o11y`, wrapping the
|
|
337
|
-
Worker with `withObservability`, and choosing useful spans, metrics, errors, and
|
|
338
|
-
LLM-usage records. The human owns the device approval, production consent, and
|
|
339
|
-
explicit destructive rotation. Studio is where people view telemetry and
|
|
340
|
-
perform manual recovery, configure System AI, and inspect app/run-attributed
|
|
341
|
-
platform usage; its o11y token control is not the normal setup path.
|
|
342
|
-
Run `npx odla-ai capabilities` for the human-readable contract or add `--json`
|
|
343
|
-
when an agent or tool needs to branch on it without scraping prose.
|
|
344
|
-
|
|
345
|
-
`setup` (and `skill install`) installs one complete offline runbook bundle at
|
|
346
|
-
`.agents/skills/`, then adds thin native adapters for Claude Code
|
|
347
|
-
(`.claude/skills/`), Codex, Cursor (`.cursor/rules/`), GitHub Copilot
|
|
348
|
-
(`.github/copilot-instructions.md`), Gemini CLI (`GEMINI.md`), and portable
|
|
349
|
-
`AGENTS.md` agents. The default is `--agent all`; select one or more with
|
|
350
|
-
`--agent claude,codex` or repeated `--agent` flags. A global install supports
|
|
351
|
-
the native Claude and Codex roots only.
|
|
352
|
-
|
|
353
|
-
Existing `AGENTS.md`, `GEMINI.md`, and Copilot instructions are preserved. The
|
|
354
|
-
installer appends a bounded odla-managed section, is idempotent, refuses
|
|
355
|
-
symlink-redirection and locally changed managed content, and lets `--force`
|
|
356
|
-
replace only odla-owned content. The local bundle includes build, migration,
|
|
357
|
-
and observability-debug procedures plus every reference they need; agents do
|
|
358
|
-
not need online docs or access to odla's private service source after setup.
|
|
359
|
-
|
|
360
|
-
After running setup, the whole prompt can be: “Set up odla in this repo using
|
|
361
|
-
the installed local odla runbook. Decide whether this is a new app or an
|
|
362
|
-
existing site to migrate, then drive it end to end. Ask me only for the device
|
|
363
|
-
approval and other human-only checkpoints.”
|
|
364
|
-
|
|
365
|
-
For programmatic callers, `installSkill()` keeps `targetDir`, `written`, and
|
|
366
|
-
`unchanged` as one unambiguous primary-root view: the latter two contain paths
|
|
367
|
-
relative to `targetDir` only. Use the additive absolute `writtenPaths` and
|
|
368
|
-
`unchangedPaths` fields to inspect every shared-bundle and adapter artifact.
|
|
369
|
-
|
|
370
|
-
`doctor` also lints for common footguns: permission rules that are literally
|
|
371
|
-
`"true"` (public writes always warn; a public `view` warns unless the
|
|
372
|
-
namespace is listed in `db.publicRead`), schema entities missing from the
|
|
373
|
-
rules map, credential files (`.dev.vars`, `.odla/*`) tracked by git, a
|
|
374
|
-
wrangler assets directory pointed at the project root or at a directory
|
|
375
|
-
containing `node_modules` (the `wrangler dev` "spawn EBADF" footgun),
|
|
376
|
-
secret-shaped values in wrangler `vars`, and a package.json script literally
|
|
377
|
-
named `deploy` (CI may auto-deploy it).
|
|
378
|
-
|
|
379
|
-
## Config
|
|
380
|
-
|
|
381
|
-
```js
|
|
382
|
-
export default {
|
|
383
|
-
platformUrl: process.env.ODLA_PLATFORM_URL ?? "https://odla.ai",
|
|
384
|
-
dbEndpoint: process.env.ODLA_ENDPOINT ?? process.env.ODLA_DB_ENDPOINT ?? "https://db.odla.ai",
|
|
385
|
-
app: { id: "my-app", name: "My App" },
|
|
386
|
-
envs: ["dev"], // add "prod" deliberately; provisioning it requires --yes
|
|
387
|
-
services: ["db", "ai", "o11y", "calendar"],
|
|
388
|
-
db: {
|
|
389
|
-
schema: "./src/odla/schema.mjs",
|
|
390
|
-
rules: "./src/odla/rules.mjs",
|
|
391
|
-
defaultRules: "deny",
|
|
392
|
-
publicRead: [], // namespaces where a `view: "true"` rule is intentional
|
|
393
|
-
},
|
|
394
|
-
ai: {
|
|
395
|
-
provider: process.env.ODLA_AI_PROVIDER ?? "anthropic",
|
|
396
|
-
keyEnv: "ANTHROPIC_API_KEY",
|
|
397
|
-
},
|
|
398
|
-
calendar: {
|
|
399
|
-
google: {
|
|
400
|
-
calendars: { dev: ["primary"] },
|
|
401
|
-
bookingPageUrl: {
|
|
402
|
-
dev: "https://calendar.google.com/calendar/appointments/schedules/…",
|
|
403
|
-
},
|
|
404
|
-
match: {
|
|
405
|
-
summaryPrefix: "Intro", // optional
|
|
406
|
-
organizerSelf: true,
|
|
407
|
-
requireAttendees: true,
|
|
408
|
-
},
|
|
409
|
-
attendeePolicy: "full", // or "hashed"
|
|
410
|
-
},
|
|
411
|
-
},
|
|
412
|
-
auth: {
|
|
413
|
-
// Publishable key (public). Created + pulled by the Clerk CLI (`npx clerk`);
|
|
414
|
-
// See the installed odla-migrate phase 3. Inline `pk_…` or "$ENV_VAR".
|
|
415
|
-
clerk: {
|
|
416
|
-
dev: "$CLERK_PUBLISHABLE_KEY",
|
|
417
|
-
prod: "$CLERK_PUBLISHABLE_KEY",
|
|
418
|
-
},
|
|
419
|
-
},
|
|
420
|
-
links: {
|
|
421
|
-
dev: "https://dev.example.com",
|
|
422
|
-
prod: "https://example.com",
|
|
423
|
-
},
|
|
424
|
-
};
|
|
425
|
-
```
|
|
426
|
-
|
|
427
|
-
`db.schema` and `db.rules` may be inline objects, JSON files, or JS modules
|
|
428
|
-
exporting `default`, `schema` / `SCHEMA`, or `rules` / `RULES`.
|
|
429
|
-
|
|
430
|
-
If schema is present and rules are omitted, `defaultRules: "deny"` generates
|
|
431
|
-
deny-all rules for every schema entity. That is the safe default for Workers
|
|
432
|
-
that mediate reads and writes with an app key.
|
|
433
|
-
|
|
434
|
-
## API reference (generated from dist/index.d.ts, v0.10.0)
|
|
435
|
-
|
|
436
|
-
```ts
|
|
437
|
-
import { SecurityReport, PlatformSecurityRun } from '@odla-ai/security';
|
|
438
|
-
import { HostedSecurityJob, GitHubConnectionStatus, GitHubSecuritySource, HostedSecurityIntentResponse, HostedSecurityPlan, HostedSecurityReport, HostedSecurityJobStatus } from '@odla-ai/security/hosted';
|
|
439
|
-
export { GitHubConnectionAttempt, GitHubConnectionStatus, GitHubSecuritySource, HostedSecurityCounts, HostedSecurityCoverage, HostedSecurityIntent, HostedSecurityIntentResponse, HostedSecurityJob, HostedSecurityJobStatus, HostedSecurityPlan, HostedSecurityPlanRoute, HostedSecurityReport, HostedSecurityReportFinding, HostedSecurityRoute } from '@odla-ai/security/hosted';
|
|
440
|
-
|
|
441
|
-
/** Injectable side-effect boundaries used to run and test the command dispatcher. */
|
|
442
|
-
interface CliDependencies {
|
|
443
|
-
fetch?: typeof fetch;
|
|
444
|
-
openUrl?: (url: string) => Promise<void>;
|
|
445
|
-
pollWait?: (milliseconds: number, signal?: AbortSignal) => Promise<void>;
|
|
446
|
-
readGitOrigin?: (cwd: string) => Promise<string>;
|
|
447
|
-
confirm?: (message: string) => Promise<boolean>;
|
|
448
|
-
stdout?: Pick<typeof console, "log" | "error">;
|
|
449
|
-
}
|
|
450
|
-
/**
|
|
451
|
-
* Parse CLI arguments and dispatch the matching odla command.
|
|
452
|
-
*
|
|
453
|
-
* The dispatcher covers project setup, platform AI administration, hosted and
|
|
454
|
-
* local security, provisioning, smoke checks, skill installation, and secret
|
|
455
|
-
* pushes. It rejects unknown commands, unsupported options, extra positionals,
|
|
456
|
-
* missing values, and errors returned by the selected command.
|
|
457
|
-
*
|
|
458
|
-
* @param argv Argument vector without the node/script prefix.
|
|
459
|
-
* @param dependencies Optional side-effect overrides for embedding and tests.
|
|
460
|
-
*/
|
|
461
|
-
declare function runCli(argv?: string[], dependencies?: CliDependencies): Promise<void>;
|
|
462
|
-
|
|
463
|
-
/** One exact platform scope obtainable through the admin device flow. */
|
|
464
|
-
type ScopedPlatformScope = "platform:ai:policy:read" | "platform:ai:policy:write" | "platform:ai:credential:read" | "platform:ai:credential:write" | "platform:ai:usage:read" | "platform:ai:audit:read" | "platform:security:self";
|
|
465
|
-
/** Inputs for obtaining one short-lived, exact-scope platform device grant. */
|
|
466
|
-
interface ScopedPlatformTokenOptions {
|
|
467
|
-
platform: string;
|
|
468
|
-
scope: ScopedPlatformScope;
|
|
469
|
-
open?: boolean;
|
|
470
|
-
fetch?: typeof fetch;
|
|
471
|
-
stdout?: Pick<typeof console, "log">;
|
|
472
|
-
openApprovalUrl?: (url: string) => Promise<void>;
|
|
473
|
-
tokenFile?: string;
|
|
474
|
-
}
|
|
475
|
-
/** Obtain/cache one exact platform scope without granting ambient admin. */
|
|
476
|
-
declare function getScopedPlatformToken(options: ScopedPlatformTokenOptions): Promise<string>;
|
|
477
|
-
|
|
478
|
-
/** Hosted platform purposes whose provider, model, and budgets an admin may route. */
|
|
479
|
-
declare const SYSTEM_AI_PURPOSES: readonly ["o11y.triage", "security.discovery", "security.validation"];
|
|
480
|
-
/** One catalog-validated, platform-funded System AI purpose. */
|
|
481
|
-
type SystemAiPurpose = (typeof SYSTEM_AI_PURPOSES)[number];
|
|
482
|
-
|
|
483
|
-
/** Inputs for one System AI policy/catalog read, policy update,
|
|
484
|
-
* credential-status read, write-only credential transfer, or metadata-only
|
|
485
|
-
* usage or admin-audit read. Provider values may come only from a named environment variable
|
|
486
|
-
* or stdin. */
|
|
487
|
-
interface AdminAiOptions {
|
|
488
|
-
action: "show" | "models" | "set" | "credentials" | "credential-set" | "usage" | "audit";
|
|
489
|
-
purpose?: string;
|
|
490
|
-
provider?: string;
|
|
491
|
-
model?: string;
|
|
492
|
-
enabled?: boolean;
|
|
493
|
-
maxInputBytes?: number;
|
|
494
|
-
maxOutputTokens?: number;
|
|
495
|
-
maxCallsPerRun?: number;
|
|
496
|
-
platform?: string;
|
|
497
|
-
token?: string;
|
|
498
|
-
json?: boolean;
|
|
499
|
-
open?: boolean;
|
|
500
|
-
fetch?: typeof fetch;
|
|
501
|
-
stdout?: Pick<typeof console, "log">;
|
|
502
|
-
openApprovalUrl?: (url: string) => Promise<void>;
|
|
503
|
-
credentialProvider?: string;
|
|
504
|
-
fromEnv?: string;
|
|
505
|
-
stdin?: boolean;
|
|
506
|
-
readStdin?: () => Promise<string>;
|
|
507
|
-
discoveryProvider?: string;
|
|
508
|
-
discoveryModel?: string;
|
|
509
|
-
validationProvider?: string;
|
|
510
|
-
validationModel?: string;
|
|
511
|
-
/** Optional metadata-only usage filters. */
|
|
512
|
-
appId?: string;
|
|
513
|
-
env?: string;
|
|
514
|
-
runId?: string;
|
|
515
|
-
limit?: number;
|
|
516
|
-
/** Separate short-lived admin-token cache; never reuses the app developer-token file. */
|
|
517
|
-
tokenFile?: string;
|
|
518
|
-
}
|
|
519
|
-
/** Read or update platform-funded AI routing and inspect attributed usage.
|
|
520
|
-
* Authentication is a short-lived,
|
|
521
|
-
* explicitly scoped device grant; ordinary app developer tokens never become
|
|
522
|
-
* platform admins. Credential writes accept values only from a named env var
|
|
523
|
-
* or stdin, transfer them once, and never place them in argv, output, or the
|
|
524
|
-
* scoped-token cache. */
|
|
525
|
-
declare function adminAi(options: AdminAiOptions): Promise<void>;
|
|
526
|
-
|
|
527
|
-
/** Stable, machine-readable division of work between the CLI, coding agent,
|
|
528
|
-
* human operator, and Studio. Printed by `odla-ai capabilities --json`. */
|
|
529
|
-
declare const CAPABILITIES: {
|
|
530
|
-
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", "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"];
|
|
531
|
-
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"];
|
|
532
|
-
readonly human: readonly ["approve the odla device code and one-off third-party logins", "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"];
|
|
533
|
-
readonly studio: readonly ["view telemetry and environment state", "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"];
|
|
534
|
-
};
|
|
535
|
-
type Output = Pick<typeof console, "log">;
|
|
536
|
-
/** Print the stable responsibility boundary for humans or agent tooling. */
|
|
537
|
-
declare function printCapabilities(json?: boolean, out?: Output): void;
|
|
538
|
-
|
|
539
|
-
declare const CALENDAR_STATES: readonly ["not_connected", "authorizing", "needs_sync", "initial_sync", "healthy", "degraded", "disconnected", "failed"];
|
|
540
|
-
type CalendarConnectionState = (typeof CALENDAR_STATES)[number];
|
|
541
|
-
/** Owner-visible, secret-free calendar connection and sync health. */
|
|
542
|
-
interface CalendarStatus {
|
|
543
|
-
env: string;
|
|
544
|
-
enabled: boolean;
|
|
545
|
-
/** True when the platform has provider credentials for this connection. */
|
|
546
|
-
connected: boolean;
|
|
547
|
-
provider: "google" | null;
|
|
548
|
-
status: CalendarConnectionState;
|
|
549
|
-
access?: "read";
|
|
550
|
-
calendars: string[];
|
|
551
|
-
attendeePolicy?: "full" | "hashed";
|
|
552
|
-
/** True once a booking projection may have established the DB privacy policy. */
|
|
553
|
-
attendeePolicyLocked?: boolean;
|
|
554
|
-
bookingPageUrl?: string | null;
|
|
555
|
-
grantedScopes: string[];
|
|
556
|
-
attemptId?: string;
|
|
557
|
-
lastSuccessfulSyncAt?: number;
|
|
558
|
-
lastFullSyncAt?: number;
|
|
559
|
-
watchExpiresAt?: number;
|
|
560
|
-
bookingCount?: number;
|
|
561
|
-
error?: {
|
|
562
|
-
code?: string;
|
|
563
|
-
message?: string;
|
|
564
|
-
};
|
|
565
|
-
}
|
|
566
|
-
/** One Google calendar the connected identity may select for mirroring. */
|
|
567
|
-
interface AvailableGoogleCalendar {
|
|
568
|
-
id: string;
|
|
569
|
-
summary?: string;
|
|
570
|
-
primary?: boolean;
|
|
571
|
-
selected?: boolean;
|
|
572
|
-
accessRole?: "freeBusyReader" | "reader" | "writer" | "owner";
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
interface CalendarLifecycleOptions {
|
|
576
|
-
configPath: string;
|
|
577
|
-
env?: string;
|
|
578
|
-
token?: string;
|
|
579
|
-
open?: boolean;
|
|
580
|
-
interactive?: boolean;
|
|
581
|
-
yes?: boolean;
|
|
582
|
-
json?: boolean;
|
|
583
|
-
fetch?: typeof fetch;
|
|
584
|
-
stdout?: Pick<typeof console, "log" | "error">;
|
|
585
|
-
openConsentUrl?: (url: string) => Promise<void>;
|
|
586
|
-
wait?: (milliseconds: number, signal?: AbortSignal) => Promise<void>;
|
|
587
|
-
pollTimeoutMs?: number;
|
|
588
|
-
now?: () => number;
|
|
589
|
-
signal?: AbortSignal;
|
|
590
|
-
}
|
|
591
|
-
/** Read the owner-visible Google connection and mirror health for one env. */
|
|
592
|
-
declare function calendarStatus(options: CalendarLifecycleOptions): Promise<CalendarStatus>;
|
|
593
|
-
/** List calendars visible to the connected Google identity for config authoring. */
|
|
594
|
-
declare function calendarCalendars(options: CalendarLifecycleOptions): Promise<AvailableGoogleCalendar[]>;
|
|
595
|
-
/** Apply the public booking page setting, then complete Google consent + initial sync. */
|
|
596
|
-
declare function calendarConnect(options: CalendarLifecycleOptions): Promise<CalendarStatus>;
|
|
597
|
-
/** Ask the hosted connector for an immediate incremental/full recovery sync. */
|
|
598
|
-
declare function calendarResync(options: CalendarLifecycleOptions): Promise<CalendarStatus>;
|
|
599
|
-
/** Stop watches and delete this connection's encrypted platform token/cursors
|
|
600
|
-
* without purging the mirror or revoking the shared Google project grant. */
|
|
601
|
-
declare function calendarDisconnect(options: CalendarLifecycleOptions): Promise<CalendarStatus>;
|
|
602
|
-
|
|
603
|
-
interface RunResult {
|
|
604
|
-
code: number;
|
|
605
|
-
stdout: string;
|
|
606
|
-
stderr: string;
|
|
607
|
-
}
|
|
608
|
-
/** Subprocess seam: injectable in tests, `defaultRunner` in production. */
|
|
609
|
-
type CommandRunner = (cmd: string, args: string[], opts?: {
|
|
610
|
-
input?: string;
|
|
611
|
-
cwd?: string;
|
|
612
|
-
}) => Promise<RunResult>;
|
|
613
|
-
|
|
614
|
-
type OdlaEnvName = string;
|
|
615
|
-
type AppRules = Record<string, {
|
|
616
|
-
view?: string;
|
|
617
|
-
create?: string;
|
|
618
|
-
update?: string;
|
|
619
|
-
delete?: string;
|
|
620
|
-
}>;
|
|
621
|
-
interface ClerkAuthConfig {
|
|
622
|
-
publishableKey?: string;
|
|
623
|
-
audience?: string;
|
|
624
|
-
mode?: "client" | "full";
|
|
625
|
-
}
|
|
626
|
-
/** Read-only event selection applied by the hosted Google calendar connector. */
|
|
627
|
-
interface GoogleCalendarMatchConfig {
|
|
628
|
-
/** Mirror only events whose summary begins with this value. */
|
|
629
|
-
summaryPrefix?: string;
|
|
630
|
-
/** Require the connected identity to organize the event. Defaults to true. */
|
|
631
|
-
organizerSelf?: boolean;
|
|
632
|
-
/** Require at least one attendee. Defaults to true. */
|
|
633
|
-
requireAttendees?: boolean;
|
|
634
|
-
}
|
|
635
|
-
/** Google Calendar intent. OAuth credentials never belong in this config. */
|
|
636
|
-
interface GoogleCalendarConfig {
|
|
637
|
-
/** One through ten provider calendar ids to mirror in each odla environment. */
|
|
638
|
-
calendars: Record<OdlaEnvName, string[]>;
|
|
639
|
-
/** Public Google Appointment Schedule URL for static embed/link mode. */
|
|
640
|
-
bookingPageUrl?: Record<OdlaEnvName, string | null>;
|
|
641
|
-
match?: GoogleCalendarMatchConfig;
|
|
642
|
-
/** Store normalized attendee addresses, or only SHA-256 match keys. */
|
|
643
|
-
attendeePolicy?: "full" | "hashed";
|
|
644
|
-
}
|
|
645
|
-
interface CalendarConfig {
|
|
646
|
-
google: GoogleCalendarConfig;
|
|
647
|
-
}
|
|
648
|
-
/** Canonical, environment-specific config sent to the calendar controller. */
|
|
649
|
-
interface CalendarServiceConfig extends Record<string, unknown> {
|
|
650
|
-
provider: "google";
|
|
651
|
-
access: "read";
|
|
652
|
-
/** Deduplicated provider ids; the hosted connector accepts at most ten. */
|
|
653
|
-
calendars: string[];
|
|
654
|
-
match: {
|
|
655
|
-
organizerSelf: boolean;
|
|
656
|
-
requireAttendees: boolean;
|
|
657
|
-
summaryPrefix?: string;
|
|
658
|
-
};
|
|
659
|
-
attendeePolicy: "full" | "hashed";
|
|
660
|
-
}
|
|
661
|
-
/** Authored `odla.config.mjs` contract consumed by doctor and provision. */
|
|
662
|
-
interface OdlaProjectConfig {
|
|
663
|
-
platformUrl?: string;
|
|
664
|
-
dbEndpoint?: string;
|
|
665
|
-
app: {
|
|
666
|
-
id: string;
|
|
667
|
-
name: string;
|
|
668
|
-
};
|
|
669
|
-
envs?: OdlaEnvName[];
|
|
670
|
-
services?: string[];
|
|
671
|
-
db?: {
|
|
672
|
-
/** Inline SerializedSchema, JSON file, or JS module path exporting default/schema. */
|
|
673
|
-
schema?: unknown;
|
|
674
|
-
/** Inline rule map, JSON file, or JS module path exporting default/rules. */
|
|
675
|
-
rules?: AppRules | string;
|
|
676
|
-
/** Generate deny-all rules from schema when rules are omitted. Defaults to true when schema exists. */
|
|
677
|
-
defaultRules?: "deny" | false;
|
|
678
|
-
/** Namespaces where a literal `view: "true"` rule is intentional (public content). */
|
|
679
|
-
publicRead?: string[];
|
|
680
|
-
};
|
|
681
|
-
ai?: {
|
|
682
|
-
provider?: string;
|
|
683
|
-
model?: string;
|
|
684
|
-
/** Env var containing the provider key to store in the platform vault. */
|
|
685
|
-
keyEnv?: string;
|
|
686
|
-
/** Vault secret name. Defaults to @odla-ai/ai's provider default. */
|
|
687
|
-
secretName?: string;
|
|
688
|
-
};
|
|
689
|
-
calendar?: CalendarConfig;
|
|
690
|
-
o11y?: {
|
|
691
|
-
/** This service's name in the collector. Defaults to the app id. */
|
|
692
|
-
service?: string;
|
|
693
|
-
/** Collector base URL. Defaults to https://o11y.odla.ai. */
|
|
694
|
-
endpoint?: string;
|
|
695
|
-
/** Release tag stamped on emitted signals. */
|
|
696
|
-
version?: string;
|
|
697
|
-
};
|
|
698
|
-
auth?: {
|
|
699
|
-
clerk?: Record<OdlaEnvName, ClerkAuthConfig | string | null | undefined>;
|
|
700
|
-
};
|
|
701
|
-
links?: Record<OdlaEnvName, string | null | undefined>;
|
|
702
|
-
local?: {
|
|
703
|
-
tokenFile?: string;
|
|
704
|
-
credentialsFile?: string;
|
|
705
|
-
devVarsFile?: string;
|
|
706
|
-
gitignore?: boolean;
|
|
707
|
-
};
|
|
708
|
-
}
|
|
709
|
-
/** Normalized project config with resolved paths, endpoints, envs, and services. */
|
|
710
|
-
interface LoadedProjectConfig extends OdlaProjectConfig {
|
|
711
|
-
configPath: string;
|
|
712
|
-
rootDir: string;
|
|
713
|
-
platformUrl: string;
|
|
714
|
-
dbEndpoint: string;
|
|
715
|
-
envs: OdlaEnvName[];
|
|
716
|
-
services: string[];
|
|
717
|
-
local: {
|
|
718
|
-
tokenFile: string;
|
|
719
|
-
credentialsFile: string;
|
|
720
|
-
devVarsFile: string;
|
|
721
|
-
gitignore: boolean;
|
|
722
|
-
};
|
|
723
|
-
}
|
|
724
|
-
/** Private mode-0600 local state written by provision and never committed. */
|
|
725
|
-
interface LocalCredentials {
|
|
726
|
-
appId: string;
|
|
727
|
-
platformUrl: string;
|
|
728
|
-
dbEndpoint: string;
|
|
729
|
-
updatedAt: string;
|
|
730
|
-
envs: Record<string, {
|
|
731
|
-
tenantId: string;
|
|
732
|
-
dbKey?: string;
|
|
733
|
-
o11yToken?: string;
|
|
734
|
-
}>;
|
|
735
|
-
}
|
|
736
|
-
/** Controls one dev-first provisioning run; production mutation requires `yes`. */
|
|
737
|
-
interface ProvisionOptions {
|
|
738
|
-
configPath: string;
|
|
739
|
-
dryRun?: boolean;
|
|
740
|
-
rotateKeys?: boolean;
|
|
741
|
-
/** Rotate only the o11y ingest token; leaves db keys unchanged. */
|
|
742
|
-
rotateO11yToken?: boolean;
|
|
743
|
-
/** Push configured Worker secrets to every configured env after provisioning. */
|
|
744
|
-
pushSecrets?: boolean;
|
|
745
|
-
writeCredentials?: boolean;
|
|
746
|
-
writeDevVars?: string | boolean;
|
|
747
|
-
token?: string;
|
|
748
|
-
/** true forces browser launch, false disables it, undefined auto-opens only for interactive terminals. */
|
|
749
|
-
open?: boolean;
|
|
750
|
-
/** Test/embedding override for terminal interactivity. Defaults to stdin/stdout TTY detection. */
|
|
751
|
-
interactive?: boolean;
|
|
752
|
-
/** Test/embedding override for opening the approval URL. Defaults to the OS browser opener. */
|
|
753
|
-
openApprovalUrl?: (url: string) => Promise<void>;
|
|
754
|
-
/** Test/embedding override for calendar connection polling. */
|
|
755
|
-
calendarPollWait?: (milliseconds: number, signal?: AbortSignal) => Promise<void>;
|
|
756
|
-
/** Maximum calendar consent + initial-sync wait. Defaults to ten minutes. */
|
|
757
|
-
calendarPollTimeoutMs?: number;
|
|
758
|
-
/** Explicit consent for a non-dry-run plan containing `prod` or `production`. */
|
|
759
|
-
yes?: boolean;
|
|
760
|
-
fetch?: typeof fetch;
|
|
761
|
-
/** Test/embedding override for Wrangler subprocesses used by `pushSecrets`. */
|
|
762
|
-
secretRunner?: CommandRunner;
|
|
763
|
-
stdout?: Pick<typeof console, "log" | "error">;
|
|
764
|
-
}
|
|
765
|
-
/** Human-reviewable, secret-free plan printed by `provision({ dryRun: true })`. */
|
|
766
|
-
interface ProvisionPlan {
|
|
767
|
-
appId: string;
|
|
768
|
-
appName: string;
|
|
769
|
-
platformUrl: string;
|
|
770
|
-
dbEndpoint: string;
|
|
771
|
-
envs: string[];
|
|
772
|
-
services: string[];
|
|
773
|
-
hasSchema: boolean;
|
|
774
|
-
hasRules: boolean;
|
|
775
|
-
aiProvider?: string;
|
|
776
|
-
}
|
|
777
|
-
/** Inputs for a read-only live environment smoke check. */
|
|
778
|
-
interface SmokeOptions {
|
|
779
|
-
configPath: string;
|
|
780
|
-
env?: string;
|
|
781
|
-
/** Developer-token override used only for owner-visible calendar health. */
|
|
782
|
-
token?: string;
|
|
783
|
-
open?: boolean;
|
|
784
|
-
interactive?: boolean;
|
|
785
|
-
openApprovalUrl?: (url: string) => Promise<void>;
|
|
786
|
-
fetch?: typeof fetch;
|
|
787
|
-
stdout?: Pick<typeof console, "log" | "error">;
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
declare const GOOGLE_CALENDAR_READ_SCOPE = "https://www.googleapis.com/auth/calendar.events.readonly";
|
|
791
|
-
/** Resolve the checked-in calendar block into one controller-safe env payload. */
|
|
792
|
-
declare function calendarServiceConfig(cfg: LoadedProjectConfig, env: string): CalendarServiceConfig;
|
|
793
|
-
/** Public Appointment Schedule URL to apply separately from connector config. */
|
|
794
|
-
declare function calendarBookingPageUrl(cfg: LoadedProjectConfig, env: string): string | null | undefined;
|
|
795
|
-
|
|
796
|
-
interface DoctorOptions {
|
|
797
|
-
configPath: string;
|
|
798
|
-
stdout?: Pick<typeof console, "log" | "error">;
|
|
799
|
-
}
|
|
800
|
-
/**
|
|
801
|
-
* Validate and summarize an odla project config entirely offline — no network
|
|
802
|
-
* calls and no file writes. Loads `configPath`, builds the provision plan, and
|
|
803
|
-
* resolves the schema and rules (synthesizing deny-all rules from the schema
|
|
804
|
-
* when `db.rules` is omitted and `db.defaultRules` isn't `false`), then prints a
|
|
805
|
-
* summary line for the app, envs, services, schema entity count, rules namespace
|
|
806
|
-
* count, and AI provider.
|
|
807
|
-
*
|
|
808
|
-
* It then collects warnings for the mistakes provision can't fix silently: a
|
|
809
|
-
* schema with no entities, a rules namespace with no matching entity, the `ai`
|
|
810
|
-
* service enabled without an `ai.provider`, `auth.clerk` entries that reference
|
|
811
|
-
* an unset env var (`$FOO`), an `ai.keyEnv` that isn't set (provider key upload
|
|
812
|
-
* will be skipped), and — when `o11y` is enabled — any env whose local
|
|
813
|
-
* credentials lack an ingest token. It also folds in the shared rule linter,
|
|
814
|
-
* git-tracked secret-shaped files, and wrangler config warnings. Prints `ok`
|
|
815
|
-
* when clean, otherwise the warning list. Purely advisory: never throws on
|
|
816
|
-
* warnings and never mutates anything.
|
|
817
|
-
*
|
|
818
|
-
* @param options.configPath Path to the `odla.config.mjs` to inspect.
|
|
819
|
-
* @param options.stdout Optional console-like sink (defaults to `console`).
|
|
820
|
-
*/
|
|
821
|
-
declare function doctor(options: DoctorOptions): Promise<void>;
|
|
822
|
-
|
|
823
|
-
interface InitOptions {
|
|
824
|
-
rootDir?: string;
|
|
825
|
-
configPath?: string;
|
|
826
|
-
appId: string;
|
|
827
|
-
name: string;
|
|
828
|
-
envs?: string[];
|
|
829
|
-
services?: string[];
|
|
830
|
-
aiProvider?: string;
|
|
831
|
-
force?: boolean;
|
|
832
|
-
stdout?: Pick<typeof console, "log" | "error">;
|
|
833
|
-
}
|
|
834
|
-
/**
|
|
835
|
-
* Scaffold a new odla project into `rootDir` (default: cwd). Writes an
|
|
836
|
-
* `odla.config.mjs` (default name, overridable via `configPath`) plus starter
|
|
837
|
-
* `src/odla/schema.mjs` (a single `notes` entity) and `src/odla/rules.mjs`
|
|
838
|
-
* (deny-all), and creates the `src/odla` and `.odla` directories. Also runs
|
|
839
|
-
* `ensureGitignore` so the local token/credentials paths are ignored.
|
|
840
|
-
*
|
|
841
|
-
* Fully local and synchronous — no network calls. The config file is only
|
|
842
|
-
* written when it doesn't already exist unless `force` is set (otherwise it
|
|
843
|
-
* throws); the schema/rules files are written only when missing (never
|
|
844
|
-
* overwritten, even with `force`). `appId` must match `^[a-z0-9][a-z0-9-]*$` or
|
|
845
|
-
* it throws. Defaults: `envs` → `["dev"]`, `services` → `["db","ai"]`,
|
|
846
|
-
* `aiProvider` → `"anthropic"` (which also picks the `keyEnv`, e.g.
|
|
847
|
-
* `ANTHROPIC_API_KEY`/`OPENAI_API_KEY`/`GOOGLE_API_KEY`).
|
|
848
|
-
*
|
|
849
|
-
* @param options.appId Slug for the app (lowercase alphanumerics and hyphens).
|
|
850
|
-
* @param options.name Human-readable app name embedded in the config.
|
|
851
|
-
* @param options.rootDir Project root (defaults to `process.cwd()`).
|
|
852
|
-
* @param options.configPath Config filename relative to root (default `odla.config.mjs`).
|
|
853
|
-
* @param options.envs Environment names (default `["dev"]`; production is an explicit opt-in).
|
|
854
|
-
* @param options.services Enabled services (default `["db","ai"]`).
|
|
855
|
-
* @param options.aiProvider AI provider slug (default `"anthropic"`).
|
|
856
|
-
* @param options.force Overwrite an existing config file instead of throwing.
|
|
857
|
-
* @param options.stdout Optional console-like sink (defaults to `console`).
|
|
858
|
-
*/
|
|
859
|
-
declare function initProject(options: InitOptions): void;
|
|
860
|
-
|
|
861
|
-
/**
|
|
862
|
-
* Provision an app end-to-end from its config — the primary deploy path, and
|
|
863
|
-
* (apart from key rotation) idempotent, so re-running is safe. Obtains a
|
|
864
|
-
* developer token, creates the registry app when absent, enables each service
|
|
865
|
-
* per env (AI also gets `setAi` with the configured provider/model), configures
|
|
866
|
-
* Clerk auth and links, then per env mints or reuses credentials only for the
|
|
867
|
-
* configured services, pushes the schema with the db key and the
|
|
868
|
-
* rules with the developer token, and stores the provider key in the tenant
|
|
869
|
-
* vault when `ai.keyEnv` is set and present. Finally writes the credentials file
|
|
870
|
-
* (mode 0600, gitignored) and, when requested, `.dev.vars`.
|
|
871
|
-
*
|
|
872
|
-
* The developer token comes from (in order) `options.token`, `$ODLA_DEV_TOKEN`,
|
|
873
|
-
* the cached `.odla` token, or a fresh device handshake — which prints a user
|
|
874
|
-
* code + approval URL and, in interactive terminals, auto-opens the browser
|
|
875
|
-
* (`open: true`/`false` forces/suppresses it). Network error bodies pass through
|
|
876
|
-
* `redactSecrets` before display.
|
|
877
|
-
*
|
|
878
|
-
* @param options.dryRun Print the resolved plan and return before any network call/write.
|
|
879
|
-
* @param options.rotateKeys Rotate db keys and o11y tokens.
|
|
880
|
-
* @param options.rotateO11yToken Rotate only the o11y token.
|
|
881
|
-
* @param options.pushSecrets Preflight Wrangler, then push each env's configured
|
|
882
|
-
* Worker secrets immediately after credential provisioning.
|
|
883
|
-
* @param options.writeDevVars `true`/a path writes `.dev.vars`; `writeCredentials: false` skips the creds file.
|
|
884
|
-
* @param options.yes Required for a non-dry-run plan containing `prod` or
|
|
885
|
-
* `production`; callers must show and review `dryRun` output first.
|
|
886
|
-
* @throws When a production plan is executed without `yes`, configuration is
|
|
887
|
-
* invalid, authorization fails, or a provisioning operation fails.
|
|
888
|
-
*/
|
|
889
|
-
declare function provision(options: ProvisionOptions): Promise<void>;
|
|
890
|
-
|
|
891
|
-
/**
|
|
892
|
-
* Return `value` with every secret-shaped substring replaced by a `[redacted]`
|
|
893
|
-
* placeholder that keeps the identifying prefix (e.g. `sk_live_[redacted]`).
|
|
894
|
-
* Matches odla db keys (`odla_sk_`/`odla_dev_`), Clerk secret keys
|
|
895
|
-
* (`sk_live_`/`sk_test_`), OpenAI keys (`sk-`), webhook signing secrets
|
|
896
|
-
* (`whsec_`), o11y tokens (`o11y_`), GitHub tokens (`ghp_`/`gho_`/`github_pat_`),
|
|
897
|
-
* and AWS access-key ids (`AKIA…`). Clerk publishable keys (`pk_test_`/
|
|
898
|
-
* `pk_live_`) are public by design and intentionally left untouched. Used to
|
|
899
|
-
* sanitize anything the CLI echoes (notably network error bodies) before it
|
|
900
|
-
* reaches stdout/stderr. Non-matching input is returned unchanged.
|
|
901
|
-
*/
|
|
902
|
-
declare function redactSecrets(value: string): string;
|
|
903
|
-
|
|
904
|
-
/** Moves locally stored configured service credentials to one Wrangler environment over stdin. */
|
|
905
|
-
interface SecretsPushOptions {
|
|
906
|
-
configPath: string;
|
|
907
|
-
env: string;
|
|
908
|
-
dryRun?: boolean;
|
|
909
|
-
/** Required to push to a prod-named env; the visible consent token in agent transcripts. */
|
|
910
|
-
yes?: boolean;
|
|
911
|
-
runner?: CommandRunner;
|
|
912
|
-
stdout?: Pick<typeof console, "log" | "error">;
|
|
913
|
-
}
|
|
914
|
-
/**
|
|
915
|
-
* Moves the env's configured db and/or o11y credentials from the private local
|
|
916
|
-
* credentials file into the Worker, piping values over stdin so they never
|
|
917
|
-
* appear on argv, in output, or in the conversation transcript.
|
|
918
|
-
*/
|
|
919
|
-
declare function secretsPush(options: SecretsPushOptions): Promise<void>;
|
|
920
|
-
|
|
921
|
-
/**
|
|
922
|
-
* Inputs for one write-only tenant-vault transfer (`secrets set` /
|
|
923
|
-
* `secrets set-clerk-key`). Values may come only from a named environment
|
|
924
|
-
* variable or stdin, so a producer command can be piped straight into the
|
|
925
|
-
* vault without the secret ever being displayed or stored on disk.
|
|
926
|
-
*/
|
|
927
|
-
interface SecretsSetOptions {
|
|
928
|
-
configPath: string;
|
|
929
|
-
env: string;
|
|
930
|
-
/** Vault secret name (`secrets set` only; `$`-prefixed names are reserved). */
|
|
931
|
-
name?: string;
|
|
932
|
-
fromEnv?: string;
|
|
933
|
-
stdin?: boolean;
|
|
934
|
-
/** Explicit consent for a prod-named env (and for sk_live_ into a non-prod env). */
|
|
935
|
-
yes?: boolean;
|
|
936
|
-
/** Developer token override; defaults to $ODLA_DEV_TOKEN, the cached token, or a device handshake. */
|
|
937
|
-
token?: string;
|
|
938
|
-
open?: boolean;
|
|
939
|
-
interactive?: boolean;
|
|
940
|
-
openApprovalUrl?: (url: string) => Promise<void>;
|
|
941
|
-
fetch?: typeof fetch;
|
|
942
|
-
readStdin?: () => Promise<string>;
|
|
943
|
-
stdout?: Pick<typeof console, "log" | "error">;
|
|
944
|
-
}
|
|
945
|
-
/**
|
|
946
|
-
* Store one named secret in the env's tenant vault (the same write-only slot
|
|
947
|
-
* Studio's Secrets panel fills), e.g. `clerk_webhook_secret` for synced auth.
|
|
948
|
-
* The value is encrypted at rest and can be read back only by that tenant's
|
|
949
|
-
* app API key — never by this CLI, Studio, or the developer token.
|
|
950
|
-
*/
|
|
951
|
-
declare function secretsSet(options: SecretsSetOptions): Promise<void>;
|
|
952
|
-
/**
|
|
953
|
-
* Store the app's Clerk secret key under the reserved `$clerk_secret` slot so
|
|
954
|
-
* odla-db can resolve the app's users (invites, member lookups). Reserved
|
|
955
|
-
* secrets are never readable by app keys; the dedicated endpoint is the only
|
|
956
|
-
* way to set one. Guards against instance/env mismatches: an sk_test_ key
|
|
957
|
-
* never belongs in a prod-named env, and an sk_live_ key entering a non-prod
|
|
958
|
-
* env requires `--yes` (live users would sync into a non-prod tenant).
|
|
959
|
-
*/
|
|
960
|
-
declare function secretsSetClerkKey(options: SecretsSetOptions): Promise<void>;
|
|
961
|
-
|
|
962
|
-
/** Built-in security coverage profile selected for a hosted reasoning run. */
|
|
963
|
-
type HostedSecurityProfile = "odla" | "cloudflare-app" | "generic";
|
|
964
|
-
/** Exact attribution and authorization need supplied to a lazy token callback. */
|
|
965
|
-
interface HostedSecurityTokenRequest {
|
|
966
|
-
platform: string;
|
|
967
|
-
appId: string;
|
|
968
|
-
env: string;
|
|
969
|
-
selfAudit: boolean;
|
|
970
|
-
/** Self-audit asks the caller for an explicitly scoped platform credential. */
|
|
971
|
-
/** Ordinary app runs use owner authority and therefore request no platform scope. */
|
|
972
|
-
scope: "platform:security:self" | null;
|
|
973
|
-
}
|
|
974
|
-
/** Local snapshot/orchestration controls for an app-attributed hosted security
|
|
975
|
-
* run. The platform supplies model routes and provider credentials. */
|
|
976
|
-
interface RunHostedSecurityOptions {
|
|
977
|
-
/** Project config; loaded for customer-app runs and ignored for self-audit. */
|
|
978
|
-
configPath?: string;
|
|
979
|
-
/** Scan odla itself under the protected odla-ai/prod identity. */
|
|
980
|
-
selfAudit?: boolean;
|
|
981
|
-
/** Repository directory to snapshot. Defaults to the config root or cwd for self-audit. */
|
|
982
|
-
target?: string;
|
|
983
|
-
/** Private artifact directory. Defaults to `<target>/.odla/security/hosted`. */
|
|
984
|
-
out?: string;
|
|
985
|
-
/** Customer environment. Must be declared in config. Self-audit always uses prod. */
|
|
986
|
-
env?: string;
|
|
987
|
-
profile?: HostedSecurityProfile;
|
|
988
|
-
maxHuntTasks?: number;
|
|
989
|
-
/** Exact acknowledgement required before any source capture or network call. */
|
|
990
|
-
sourceDisclosureAck?: "redacted";
|
|
991
|
-
/** Optional client correlation id; the platform returns the authoritative run id. */
|
|
992
|
-
runId?: string;
|
|
993
|
-
/** Platform override. Customer runs otherwise use config.platformUrl. */
|
|
994
|
-
platform?: string;
|
|
995
|
-
/** Injected app credential; for self-audit this must be explicitly scoped by the caller. */
|
|
996
|
-
token?: string;
|
|
997
|
-
/** Lazy token acquisition. Receives the exact app/env and required scope. */
|
|
998
|
-
getToken?: (request: HostedSecurityTokenRequest) => string | Promise<string>;
|
|
999
|
-
fetch?: typeof fetch;
|
|
1000
|
-
signal?: AbortSignal;
|
|
1001
|
-
stdout?: Pick<typeof console, "log" | "error">;
|
|
1002
|
-
}
|
|
1003
|
-
/** Completed local report, public platform run metadata, and private artifact path. */
|
|
1004
|
-
interface HostedSecurityResult {
|
|
1005
|
-
report: SecurityReport;
|
|
1006
|
-
run: Readonly<PlatformSecurityRun>;
|
|
1007
|
-
output: string;
|
|
1008
|
-
}
|
|
1009
|
-
/**
|
|
1010
|
-
* Run the hosted, redacted-source security harness for an odla app or odla's
|
|
1011
|
-
* protected self-audit identity. Provider/model selection and provider secrets
|
|
1012
|
-
* remain platform-owned; this function accepts only an app/scoped bearer and
|
|
1013
|
-
* the opaque role grants remain inside @odla-ai/security's reasoner closures.
|
|
1014
|
-
*/
|
|
1015
|
-
declare function runHostedSecurity(options: RunHostedSecurityOptions): Promise<HostedSecurityResult>;
|
|
1016
|
-
|
|
1017
|
-
/**
|
|
1018
|
-
* The hosted-security client surface. The WIRE types live in @odla-ai/security/hosted — one
|
|
1019
|
-
* definition shared with the dashboard and the server that produces them. Re-exported here so
|
|
1020
|
-
* this module stays the single import path for the rest of the CLI.
|
|
1021
|
-
*
|
|
1022
|
-
* What remains below is what is genuinely the CLI's own: transport controls (platform origin,
|
|
1023
|
-
* token, fetch, AbortSignal) that no other client shares.
|
|
1024
|
-
*/
|
|
1025
|
-
|
|
1026
|
-
/** Common authenticated transport controls for hosted-security requests. */
|
|
1027
|
-
interface HostedSecurityRequestOptions {
|
|
1028
|
-
platform: string;
|
|
1029
|
-
token: string;
|
|
1030
|
-
fetch?: typeof fetch;
|
|
1031
|
-
signal?: AbortSignal;
|
|
1032
|
-
}
|
|
1033
|
-
/** Options for browser-mediated connection of one exact GitHub repository. */
|
|
1034
|
-
interface ConnectGitHubSecuritySourceOptions extends HostedSecurityRequestOptions {
|
|
1035
|
-
appId: string;
|
|
1036
|
-
env: string;
|
|
1037
|
-
/** Exact owner/name repository requested before GitHub approval. */
|
|
1038
|
-
repository: string;
|
|
1039
|
-
/** false prints but does not launch the install URL. Defaults to true. */
|
|
1040
|
-
open?: boolean;
|
|
1041
|
-
openInstallUrl?: (url: string) => Promise<void>;
|
|
1042
|
-
/** Poll interval. The server attempt expiry remains authoritative. */
|
|
1043
|
-
pollIntervalMs?: number;
|
|
1044
|
-
pollTimeoutMs?: number;
|
|
1045
|
-
wait?: (milliseconds: number, signal?: AbortSignal) => Promise<void>;
|
|
1046
|
-
now?: () => number;
|
|
1047
|
-
stdout?: Pick<typeof console, "log">;
|
|
1048
|
-
}
|
|
1049
|
-
/** Options for listing GitHub sources or reading the plan for one app environment. */
|
|
1050
|
-
interface ListGitHubSecuritySourcesOptions extends HostedSecurityRequestOptions {
|
|
1051
|
-
appId: string;
|
|
1052
|
-
env: string;
|
|
1053
|
-
}
|
|
1054
|
-
/** Inputs for fetching the server-authored execution preview before enqueue. */
|
|
1055
|
-
interface GetHostedSecurityIntentOptions extends HostedSecurityRequestOptions {
|
|
1056
|
-
appId: string;
|
|
1057
|
-
env: string;
|
|
1058
|
-
sourceId: string;
|
|
1059
|
-
ref?: string;
|
|
1060
|
-
profile?: "odla" | "cloudflare-app" | "generic";
|
|
1061
|
-
}
|
|
1062
|
-
/** Options for revoking odla access to one saved GitHub source. */
|
|
1063
|
-
interface DisconnectGitHubSecuritySourceOptions extends HostedSecurityRequestOptions {
|
|
1064
|
-
appId: string;
|
|
1065
|
-
sourceId: string;
|
|
1066
|
-
}
|
|
1067
|
-
/** Options for enqueueing a commit-pinned hosted security review. */
|
|
1068
|
-
interface StartHostedSecurityJobOptions extends HostedSecurityRequestOptions {
|
|
1069
|
-
appId: string;
|
|
1070
|
-
env: string;
|
|
1071
|
-
sourceId: string;
|
|
1072
|
-
ref?: string;
|
|
1073
|
-
profile?: "odla" | "cloudflare-app" | "generic";
|
|
1074
|
-
clientRequestId?: string;
|
|
1075
|
-
/** Versions shown in the disclosure preflight. The server rejects stale consent. */
|
|
1076
|
-
expectedPolicyVersions: {
|
|
1077
|
-
discovery: number;
|
|
1078
|
-
validation: number;
|
|
1079
|
-
};
|
|
1080
|
-
/** Digest copied from the plan the app owner explicitly reviewed. */
|
|
1081
|
-
expectedPlanDigest: `sha256:${string}`;
|
|
1082
|
-
/** Digest copied from the exact server-authored source/ref/profile preview. */
|
|
1083
|
-
expectedExecutionDigest: `sha256:${string}`;
|
|
1084
|
-
/** Explicit disclosure acknowledgement; GitHub read access alone is not consent. */
|
|
1085
|
-
sourceDisclosureAck?: "redacted";
|
|
1086
|
-
}
|
|
1087
|
-
/** Options for reading one hosted security job or its report. */
|
|
1088
|
-
interface GetHostedSecurityJobOptions extends HostedSecurityRequestOptions {
|
|
1089
|
-
appId: string;
|
|
1090
|
-
jobId: string;
|
|
1091
|
-
}
|
|
1092
|
-
/** Options for listing hosted security jobs in one app environment. */
|
|
1093
|
-
interface ListHostedSecurityJobsOptions extends HostedSecurityRequestOptions {
|
|
1094
|
-
appId: string;
|
|
1095
|
-
env: string;
|
|
1096
|
-
}
|
|
1097
|
-
/** Polling controls for following one hosted job to a terminal state. */
|
|
1098
|
-
interface FollowHostedSecurityJobOptions extends GetHostedSecurityJobOptions {
|
|
1099
|
-
pollIntervalMs?: number;
|
|
1100
|
-
pollTimeoutMs?: number;
|
|
1101
|
-
wait?: (milliseconds: number, signal?: AbortSignal) => Promise<void>;
|
|
1102
|
-
now?: () => number;
|
|
1103
|
-
onUpdate?: (job: Readonly<HostedSecurityJob>) => void;
|
|
1104
|
-
}
|
|
1105
|
-
|
|
1106
|
-
/** Begin GitHub App installation, launch its server-issued GitHub URL, and
|
|
1107
|
-
* poll the exact attempt until the callback has connected a source. */
|
|
1108
|
-
declare function connectGitHubSecuritySource(options: ConnectGitHubSecuritySourceOptions): Promise<GitHubConnectionStatus>;
|
|
1109
|
-
/** List repository sources the current app owner connected for one environment. */
|
|
1110
|
-
declare function listGitHubSecuritySources(options: ListGitHubSecuritySourcesOptions): Promise<GitHubSecuritySource[]>;
|
|
1111
|
-
/** Revoke odla's use of one saved source without requiring a GitHub-side App
|
|
1112
|
-
* uninstall. The server marks the source deleted and rejects new jobs. */
|
|
1113
|
-
declare function disconnectGitHubSecuritySource(options: DisconnectGitHubSecuritySourceOptions): Promise<void>;
|
|
1114
|
-
/** Parse an HTTPS, ssh://, or git@github.com origin without retaining embedded
|
|
1115
|
-
* credentials. Only github.com owner/name remotes are accepted. */
|
|
1116
|
-
declare function repositoryFromGitRemote(remoteInput: string): string;
|
|
1117
|
-
/** Read the current repository's origin without invoking a shell. */
|
|
1118
|
-
declare function inferGitHubRepository(cwd?: string, readOrigin?: (cwd: string) => Promise<string>): Promise<string>;
|
|
1119
|
-
|
|
1120
|
-
/** Fetch the atomic processing-plan and source/ref/profile execution preview. */
|
|
1121
|
-
declare function getHostedSecurityIntent(options: GetHostedSecurityIntentOptions): Promise<HostedSecurityIntentResponse>;
|
|
1122
|
-
|
|
1123
|
-
/** Read the admin-selected routes, budgets, readiness, disclosure boundary,
|
|
1124
|
-
* and digest that must be acknowledged when a hosted review is enqueued. */
|
|
1125
|
-
declare function getHostedSecurityPlan(options: ListGitHubSecuritySourcesOptions): Promise<HostedSecurityPlan>;
|
|
1126
|
-
/** Enqueue a commit-pinned server-side review. The server resolves sourceId to
|
|
1127
|
-
* its saved GitHub App installation; clients cannot choose an installation or
|
|
1128
|
-
* pass a PAT. */
|
|
1129
|
-
declare function startHostedSecurityJob(options: StartHostedSecurityJobOptions): Promise<HostedSecurityJob>;
|
|
1130
|
-
/** Read one bounded hosted job status without an archive or explicit source excerpt. */
|
|
1131
|
-
declare function getHostedSecurityJob(options: GetHostedSecurityJobOptions): Promise<HostedSecurityJob>;
|
|
1132
|
-
/** List bounded, newest-first job metadata for an app environment. */
|
|
1133
|
-
declare function listHostedSecurityJobs(options: ListHostedSecurityJobsOptions): Promise<HostedSecurityJob[]>;
|
|
1134
|
-
/** Poll one exact job until it reaches a terminal state. */
|
|
1135
|
-
declare function followHostedSecurityJob(options: FollowHostedSecurityJobOptions): Promise<HostedSecurityJob>;
|
|
1136
|
-
/** Fetch the bounded normalized report projection for a completed hosted job. */
|
|
1137
|
-
declare function getHostedSecurityReport(options: GetHostedSecurityJobOptions): Promise<HostedSecurityReport>;
|
|
1138
|
-
/** Return whether a hosted job status can no longer transition. */
|
|
1139
|
-
declare function isTerminalHostedSecurityStatus(status: HostedSecurityJobStatus): boolean;
|
|
1140
|
-
|
|
1141
|
-
/** Agent harnesses with a first-class local adapter. */
|
|
1142
|
-
declare const AGENT_HARNESSES: readonly ["claude", "codex", "cursor", "copilot", "gemini", "agents"];
|
|
1143
|
-
/** A supported coding-agent harness. `agents` is the portable `AGENTS.md` adapter. */
|
|
1144
|
-
type AgentHarness = (typeof AGENT_HARNESSES)[number];
|
|
1145
|
-
/** A harness name accepted by setup; `all` expands to every project-local adapter. */
|
|
1146
|
-
type AgentHarnessSelector = AgentHarness | "all";
|
|
1147
|
-
/** Controls project-local or global installation of the bundled agent runbooks. */
|
|
1148
|
-
interface SkillInstallOptions {
|
|
1149
|
-
/** Project directory receiving the shared runbooks and harness adapters. Defaults to cwd. */
|
|
1150
|
-
dir?: string;
|
|
1151
|
-
/** Install user-wide Claude and/or Codex skills instead of project adapters. */
|
|
1152
|
-
global?: boolean;
|
|
1153
|
-
/** Harnesses to install. The programmatic compatibility default is `claude`; the CLI passes `all`. */
|
|
1154
|
-
harnesses?: AgentHarnessSelector[];
|
|
1155
|
-
/** Overwrite locally modified odla-managed files or managed instruction sections. */
|
|
1156
|
-
force?: boolean;
|
|
1157
|
-
/** Test/embedding override for the home directory. */
|
|
1158
|
-
homeDir?: string;
|
|
1159
|
-
/** Test/embedding override for `$CODEX_HOME`. */
|
|
1160
|
-
codexHomeDir?: string;
|
|
1161
|
-
/** Test/embedding override for the bundled skills directory. */
|
|
1162
|
-
sourceDir?: string;
|
|
1163
|
-
stdout?: Pick<typeof console, "log" | "error">;
|
|
1164
|
-
}
|
|
1165
|
-
/** One harness adapter and the directories or files through which it discovers odla. */
|
|
1166
|
-
interface HarnessInstallResult {
|
|
1167
|
-
harness: AgentHarness;
|
|
1168
|
-
targets: string[];
|
|
1169
|
-
}
|
|
1170
|
-
/** Files written or left unchanged by an idempotent agent-runbook installation. */
|
|
1171
|
-
interface SkillInstallResult {
|
|
1172
|
-
/** Primary native skill directory, retained for compatibility with earlier callers. */
|
|
1173
|
-
targetDir: string;
|
|
1174
|
-
/** Files changed directly under `targetDir`, relative to that directory. */
|
|
1175
|
-
written: string[];
|
|
1176
|
-
/** Files already current directly under `targetDir`, relative to that directory. */
|
|
1177
|
-
unchanged: string[];
|
|
1178
|
-
/** Absolute paths of every changed shared-runbook or adapter file. */
|
|
1179
|
-
writtenPaths: string[];
|
|
1180
|
-
/** Absolute paths of every already-current shared-runbook or adapter file. */
|
|
1181
|
-
unchangedPaths: string[];
|
|
1182
|
-
harnesses: HarnessInstallResult[];
|
|
1183
|
-
}
|
|
1184
|
-
/**
|
|
1185
|
-
* Installs one shared offline runbook tree plus thin native adapters for the
|
|
1186
|
-
* selected coding-agent harnesses. Project installs use `.agents/skills/` as
|
|
1187
|
-
* the canonical bundle; Claude Code, Cursor, Copilot, Gemini, and generic
|
|
1188
|
-
* `AGENTS.md` adapters point to it. Global installs support the native Claude
|
|
1189
|
-
* and Codex skill roots only.
|
|
1190
|
-
*
|
|
1191
|
-
* Installation is idempotent and planned before any write: an odla-managed
|
|
1192
|
-
* file changed by the user aborts the whole operation unless `force` is set.
|
|
1193
|
-
* Existing `AGENTS.md`, `GEMINI.md`, and Copilot instructions are preserved;
|
|
1194
|
-
* only the bounded odla-managed section is appended or replaced.
|
|
1195
|
-
*/
|
|
1196
|
-
declare function installSkill(options?: SkillInstallOptions): SkillInstallResult;
|
|
1197
|
-
|
|
1198
|
-
/**
|
|
1199
|
-
* Verify a live, already-provisioned environment end-to-end. Resolves the target
|
|
1200
|
-
* env (`options.env`, else `dev`, else the first declared env) and requires it to
|
|
1201
|
-
* be declared in the config. Reads the local credentials file and checks that it
|
|
1202
|
-
* belongs to this app and holds a `tenantId` + `dbKey` for the env — otherwise it
|
|
1203
|
-
* throws pointing the user at `odla-ai provision --write-dev-vars`.
|
|
1204
|
-
*
|
|
1205
|
-
* It then makes real network calls: fetches the registry public-config (and, when
|
|
1206
|
-
* `ai.provider` is configured, asserts the live provider matches), fetches the
|
|
1207
|
-
* live db schema with the db key and asserts every entity from the local schema
|
|
1208
|
-
* is present, and runs a `count` aggregate against the first entity to confirm
|
|
1209
|
-
* the db answers queries. Progress lines are printed and it ends with `ok`.
|
|
1210
|
-
* Read-only — it writes nothing and throws on the first mismatch or failed
|
|
1211
|
-
* request.
|
|
1212
|
-
*
|
|
1213
|
-
* @param options.configPath Path to the `odla.config.mjs`.
|
|
1214
|
-
* @param options.env Env to check (default `dev`, else the first declared env).
|
|
1215
|
-
* @param options.fetch Injectable `fetch` (for tests/embedding).
|
|
1216
|
-
* @param options.stdout Optional console-like sink (defaults to `console`).
|
|
1217
|
-
*/
|
|
1218
|
-
declare function smoke(options: SmokeOptions): Promise<void>;
|
|
1219
|
-
|
|
1220
|
-
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 };
|
|
1221
|
-
```
|