@odla-ai/cli 0.4.0 → 0.5.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/dist/index.js CHANGED
@@ -1,18 +1,24 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ AGENT_HARNESSES,
4
+ CAPABILITIES,
3
5
  doctor,
4
6
  initProject,
5
7
  installSkill,
8
+ printCapabilities,
6
9
  provision,
7
10
  redactSecrets,
8
11
  runCli,
9
12
  secretsPush,
10
13
  smoke
11
- } from "./chunk-UWT7C6VT.js";
14
+ } from "./chunk-7WZIZCGA.js";
12
15
  export {
16
+ AGENT_HARNESSES,
17
+ CAPABILITIES,
13
18
  doctor,
14
19
  initProject,
15
20
  installSkill,
21
+ printCapabilities,
16
22
  provision,
17
23
  redactSecrets,
18
24
  runCli,
package/llms.txt CHANGED
@@ -1,16 +1,17 @@
1
1
  # @odla-ai/cli — LLM context
2
2
 
3
- > Project-neutral CLI for provisioning odla apps, database schemas, AI settings, and local runtime files.
3
+ > Agent-operable CLI for provisioning odla apps, services, credentials, Worker secrets, and local runtime files.
4
4
 
5
- > ⚠️ **Experimentalan agentic-coding experiment.** This package is built and
6
- > operated by autonomous coding agents as an experiment in agentic loops. APIs
7
- > change without notice and nothing here is production-hardened. **Use at your
8
- > own risk.**
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
9
 
10
10
  Project-neutral provisioning CLI for odla apps. It creates and validates an
11
11
  `odla.config.mjs`, then uses that config to register an app, enable services,
12
12
  push odla-db schema/rules, configure platform AI, configure Clerk auth, record
13
- deployment links, and write local runtime credentials.
13
+ deployment links, provision o11y ingest credentials, and transfer local or
14
+ deployed Worker secrets without printing them.
14
15
 
15
16
  It does not know about any specific app. App identity, environments, services,
16
17
  schema, rules, auth, AI provider, and links all come from config.
@@ -28,7 +29,8 @@ For a project you keep working in, install it as a dev dependency so the
28
29
  shorter `npx odla-ai` form works and the version is pinned by your lockfile:
29
30
 
30
31
  ```bash
31
- npm i -D @odla-ai/cli
32
+ npm view @odla-ai/cli@0.5.0 version
33
+ npm i -D --save-exact @odla-ai/cli@0.5.0
32
34
  ```
33
35
 
34
36
  ## Prerequisites
@@ -48,10 +50,13 @@ npm i -D @odla-ai/cli
48
50
  ## Commands
49
51
 
50
52
  ```bash
53
+ npx odla-ai setup
51
54
  npx odla-ai init --app-id my-app --name "My App"
52
55
  npx odla-ai doctor
56
+ npx odla-ai capabilities --json
57
+ # install SDKs, write the Worker, and create wrangler.jsonc before secret push
53
58
  npx odla-ai provision --dry-run
54
- npx odla-ai provision --write-dev-vars
59
+ npx odla-ai provision --write-dev-vars --push-secrets
55
60
  npx odla-ai smoke --env dev
56
61
  npx odla-ai secrets push --env dev
57
62
  npx odla-ai skill install
@@ -65,8 +70,16 @@ npx odla-ai version
65
70
  - `src/odla/rules.mjs`
66
71
  - `.gitignore` entries for local credentials
67
72
 
73
+ New configs contain only the `dev` environment. Add `prod` explicitly after
74
+ the development flow is healthy; `provision` refuses to mutate `prod` or
75
+ `production` without `--yes` and supports `--dry-run` for review.
76
+
68
77
  `provision` performs the standard safe setup flow:
69
78
 
79
+ When using `--push-secrets`, create the Worker and its Wrangler config first.
80
+ The CLI checks that config and `wrangler whoami` before it issues or rotates a
81
+ shown-once credential.
82
+
70
83
  1. Gets an `odla_dev_...` token by device handshake, or reuses
71
84
  `ODLA_DEV_TOKEN` / `.odla/dev-token.json`.
72
85
  In an interactive terminal it opens the approval page in your browser when
@@ -75,14 +88,28 @@ npx odla-ai version
75
88
  best-effort; the printed URL and code always remain the fallback.
76
89
  2. Creates the platform app if needed.
77
90
  3. Enables configured services in every configured environment.
78
- 4. Mints or reuses each env's odla-db app key.
91
+ 4. Mints or reuses each env's configured service credentials: an odla-db app
92
+ key for `db` and an ingest token for `o11y`.
79
93
  5. Pushes the configured schema and rules.
80
94
  6. Configures platform AI and stores provider keys in the tenant vault when the
81
95
  configured key env var is set.
82
96
  7. Writes `.odla/credentials.local.json` with mode `0600`.
83
-
84
- Pass `--rotate-keys` to mint fresh db keys. Pass `--no-write-credentials` to
85
- skip writing the local credentials file.
97
+ 8. With `--write-dev-vars`, writes the local Worker values to `.dev.vars`; with
98
+ `--push-secrets`, transfers the configured service secrets to the matching
99
+ deployed Worker environment over Wrangler stdin.
100
+
101
+ Plain reruns are idempotent. Pass `--rotate-o11y-token` only when deliberately
102
+ invalidating and replacing the o11y token; combine it with `--push-secrets` so
103
+ the replacement reaches the Worker in the same run. `--rotate-keys` remains the
104
+ broader credential rotation. Production mutation or secret transfer requires
105
+ `--yes`. Pass `--no-write-credentials` to skip writing the local credentials
106
+ file; it cannot be combined with an operation that would issue a shown-once
107
+ credential.
108
+
109
+ Rotation and Wrangler secret replacement are not a distributed transaction.
110
+ The CLI preflights Wrangler first and persists the replacement before pushing;
111
+ if that final push still fails, follow the printed `secrets push --env ...`
112
+ retry. Do not run the rotation flag again.
86
113
 
87
114
  `smoke` verifies a provisioned environment from local credentials. It fetches
88
115
  the platform public config, checks the configured AI provider, fetches the live
@@ -90,23 +117,68 @@ odla-db schema with the tenant key, compares expected schema entities, and runs
90
117
  a count aggregate against the first entity. It fails early with a clear message
91
118
  when provisioning has not written `.odla/credentials.local.json`.
92
119
 
93
- `secrets push --env <env>` moves the env's odla-db key from
94
- `.odla/credentials.local.json` into the deployed Worker by piping it over
95
- stdin to `wrangler secret put ODLA_API_KEY` the value never appears on
96
- argv, in output, or in an agent's transcript. It preflights `wrangler whoami`
97
- and the presence of a wrangler config file. The env `prod`/`production`
98
- targets the top-level wrangler environment (no `--env` flag is passed to
99
- wrangler) and requires `--yes`; every other env maps to wrangler's
100
- `--env <name>`. `--dry-run` prints a redacted plan without spawning anything.
101
-
102
- `skill install` copies the Claude Code skills bundled with this package
103
- (currently `odla-migrate`, the phased GitHub Pages odla migration
104
- procedure) into the project's `.claude/skills/`, or into `~/.claude/skills/`
105
- with `--global`. Re-runs are idempotent; a locally modified skill file is
106
- never overwritten without `--force`. The skill's reference runbook is served
107
- at <https://odla.ai/llms-migrate.txt>; the human companion "Moving your site
108
- to odla" (accounts, the approval code, costs) lives in the odla docs after
109
- sign-in.
120
+ The bundled build/migration skills add a passive pre-ship gate with
121
+ `@odla-ai/security`: after the exact-version availability check, run
122
+ `npm i -D --save-exact @odla-ai/security@0.1.0`, then
123
+ `npx odla-security scan . --profile odla --out .odla/security/pre-ship --fail-on high --fail-on-candidates critical`.
124
+ This is a separate binary, not a hidden `odla-ai` subcommand; it makes no model
125
+ calls and does not execute target code.
126
+ Before installing the exact release, require
127
+ `npm view @odla-ai/security@0.1.0 version` to succeed before installation. An
128
+ exact-version `E404` means the release is unavailable, not that the security
129
+ preflight passed, and does not prove the package name is absent. odla's own
130
+ engineering environment uses an equivalent internal gate; customer projects
131
+ should use the published `odla-security` command above.
132
+
133
+ `secrets push --env <env>` is the narrower recovery/retry command. It moves the
134
+ configured env's odla-db key and/or o11y ingest token from
135
+ `.odla/credentials.local.json` into the deployed Worker by piping each value
136
+ over stdin to `wrangler secret put`; values never appear on argv, in output, or
137
+ in an agent's transcript. It preflights `wrangler whoami` and the presence of a
138
+ wrangler config file. The env `prod`/`production` targets the top-level
139
+ wrangler environment (no `--env` flag is passed to Wrangler) and requires
140
+ `--yes`; every other env maps to `wrangler --env <name>`. `--dry-run` prints a
141
+ redacted plan without spawning anything. For the normal path, use
142
+ `provision --write-dev-vars --push-secrets` so service enablement, credential
143
+ issuance, local config, and deployed secret transfer stay one composition.
144
+
145
+ ## Who does what
146
+
147
+ If a change is deterministic from `odla.config.mjs`, the CLI owns it: app and
148
+ service enablement, credential issuance and local persistence, `.dev.vars`,
149
+ schema/rules/auth/AI configuration, and Wrangler secret transfer. The coding
150
+ agent owns application semantics: installing `@odla-ai/o11y`, wrapping the
151
+ Worker with `withObservability`, and choosing useful spans, metrics, errors, and
152
+ LLM-usage records. The human owns the device approval, production consent, and
153
+ explicit destructive rotation. Studio is where people view telemetry and
154
+ perform manual recovery; its token control is not the normal setup path.
155
+ Run `npx odla-ai capabilities` for the human-readable contract or add `--json`
156
+ when an agent or tool needs to branch on it without scraping prose.
157
+
158
+ `setup` (and `skill install`) installs one complete offline runbook bundle at
159
+ `.agents/skills/`, then adds thin native adapters for Claude Code
160
+ (`.claude/skills/`), Codex, Cursor (`.cursor/rules/`), GitHub Copilot
161
+ (`.github/copilot-instructions.md`), Gemini CLI (`GEMINI.md`), and portable
162
+ `AGENTS.md` agents. The default is `--agent all`; select one or more with
163
+ `--agent claude,codex` or repeated `--agent` flags. A global install supports
164
+ the native Claude and Codex roots only.
165
+
166
+ Existing `AGENTS.md`, `GEMINI.md`, and Copilot instructions are preserved. The
167
+ installer appends a bounded odla-managed section, is idempotent, refuses
168
+ symlink-redirection and locally changed managed content, and lets `--force`
169
+ replace only odla-owned content. The local bundle includes build, migration,
170
+ and observability-debug procedures plus every reference they need; agents do
171
+ not need online docs or access to odla's private service source after setup.
172
+
173
+ After running setup, the whole prompt can be: “Set up odla in this repo using
174
+ the installed local odla runbook. Decide whether this is a new app or an
175
+ existing site to migrate, then drive it end to end. Ask me only for the device
176
+ approval and other human-only checkpoints.”
177
+
178
+ For programmatic callers, `installSkill()` keeps `targetDir`, `written`, and
179
+ `unchanged` as one unambiguous primary-root view: the latter two contain paths
180
+ relative to `targetDir` only. Use the additive absolute `writtenPaths` and
181
+ `unchangedPaths` fields to inspect every shared-bundle and adapter artifact.
110
182
 
111
183
  `doctor` also lints for common footguns: permission rules that are literally
112
184
  `"true"` (public writes always warn; a public `view` warns unless the
@@ -124,8 +196,8 @@ export default {
124
196
  platformUrl: process.env.ODLA_PLATFORM_URL ?? "https://odla.ai",
125
197
  dbEndpoint: process.env.ODLA_ENDPOINT ?? process.env.ODLA_DB_ENDPOINT ?? "https://db.odla.ai",
126
198
  app: { id: "my-app", name: "My App" },
127
- envs: ["prod", "dev"],
128
- services: ["db", "ai"],
199
+ envs: ["dev"], // add "prod" deliberately; provisioning it requires --yes
200
+ services: ["db", "ai", "o11y"],
129
201
  db: {
130
202
  schema: "./src/odla/schema.mjs",
131
203
  rules: "./src/odla/rules.mjs",
@@ -137,6 +209,8 @@ export default {
137
209
  keyEnv: "ANTHROPIC_API_KEY",
138
210
  },
139
211
  auth: {
212
+ // Publishable key (public). Created + pulled by the Clerk CLI (`npx clerk`);
213
+ // See the installed odla-migrate phase 3. Inline `pk_…` or "$ENV_VAR".
140
214
  clerk: {
141
215
  dev: "$CLERK_PUBLISHABLE_KEY",
142
216
  prod: "$CLERK_PUBLISHABLE_KEY",
@@ -156,15 +230,69 @@ If schema is present and rules are omitted, `defaultRules: "deny"` generates
156
230
  deny-all rules for every schema entity. That is the safe default for Workers
157
231
  that mediate reads and writes with an app key.
158
232
 
159
- ## API reference (generated from dist/index.d.ts, v0.4.0)
233
+ ## API reference (generated from dist/index.d.ts, v0.5.0)
160
234
 
161
235
  ```ts
236
+ /**
237
+ * Parse CLI arguments and dispatch to the matching command — the entry point
238
+ * `bin.ts` invokes. `argv` defaults to `process.argv.slice(2)`; the first
239
+ * positional selects the command and the rest are parsed into flags (supporting
240
+ * `--flag value`, `--flag=value`, boolean `--flag`, `--no-flag`, and repeated
241
+ * flags collected into arrays).
242
+ *
243
+ * Recognized commands: `version`/`-v`/`--version` and `help`/`-h`/`--help` print
244
+ * and return; `init` scaffolds a project (requires `--app-id` and `--name`);
245
+ * `doctor` validates config offline; `capabilities` prints the responsibility
246
+ * boundary; `provision` runs the full provision (including optional secret
247
+ * rotation, local vars, and deployed secret push); `smoke` checks a live env;
248
+ * `setup` and `skill install` install the bundled offline runbooks for Claude
249
+ * Code, Codex, Cursor, Copilot, Gemini, and `AGENTS.md`-aware agents; and
250
+ * `secrets push` pipes the env's configured db/o11y secrets into the Worker via
251
+ * Wrangler (requires `--env`). Throws on an unknown command/subcommand, unsupported option, extra
252
+ * positional argument, missing required value, or a dispatched command error.
253
+ *
254
+ * @param argv Argument vector without the node/script prefix (default
255
+ * `process.argv.slice(2)`).
256
+ */
162
257
  declare function runCli(argv?: string[]): Promise<void>;
163
258
 
259
+ /** Stable, machine-readable division of work between the CLI, coding agent,
260
+ * human operator, and Studio. Printed by `odla-ai capabilities --json`. */
261
+ declare const CAPABILITIES: {
262
+ 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", "push db schema/rules and configure platform AI, auth, and deployment links", "validate config offline and smoke-test a provisioned db environment"];
263
+ 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"];
264
+ readonly human: readonly ["approve the odla device code and one-off third-party logins", "consent to production changes with --yes", "request destructive credential rotation explicitly", "review application semantics, security findings, releases, and merges"];
265
+ readonly studio: readonly ["view telemetry and environment state", "perform manual credential recovery when the CLI's local shown-once copy is unavailable"];
266
+ };
267
+ type Output = Pick<typeof console, "log">;
268
+ /** Print the stable responsibility boundary for humans or agent tooling. */
269
+ declare function printCapabilities(json?: boolean, out?: Output): void;
270
+
164
271
  interface DoctorOptions {
165
272
  configPath: string;
166
273
  stdout?: Pick<typeof console, "log" | "error">;
167
274
  }
275
+ /**
276
+ * Validate and summarize an odla project config entirely offline — no network
277
+ * calls and no file writes. Loads `configPath`, builds the provision plan, and
278
+ * resolves the schema and rules (synthesizing deny-all rules from the schema
279
+ * when `db.rules` is omitted and `db.defaultRules` isn't `false`), then prints a
280
+ * summary line for the app, envs, services, schema entity count, rules namespace
281
+ * count, and AI provider.
282
+ *
283
+ * It then collects warnings for the mistakes provision can't fix silently: a
284
+ * schema with no entities, a rules namespace with no matching entity, the `ai`
285
+ * service enabled without an `ai.provider`, `auth.clerk` entries that reference
286
+ * an unset env var (`$FOO`), an `ai.keyEnv` that isn't set (provider key upload
287
+ * will be skipped), and — when `o11y` is enabled — any env whose local
288
+ * credentials lack an ingest token. It also folds in the shared rule linter,
289
+ * git-tracked secret-shaped files, and wrangler config warnings. Prints `ok`
290
+ * when clean, otherwise the warning list. Purely advisory: never throws on
291
+ * warnings and never mutates anything.
292
+ *
293
+ * @param options.configPath Path to the `odla.config.mjs` to inspect.
294
+ * @param options.stdout Optional console-like sink (defaults to `console`).
295
+ */
168
296
  declare function doctor(options: DoctorOptions): Promise<void>;
169
297
 
170
298
  interface InitOptions {
@@ -178,8 +306,44 @@ interface InitOptions {
178
306
  force?: boolean;
179
307
  stdout?: Pick<typeof console, "log" | "error">;
180
308
  }
309
+ /**
310
+ * Scaffold a new odla project into `rootDir` (default: cwd). Writes an
311
+ * `odla.config.mjs` (default name, overridable via `configPath`) plus starter
312
+ * `src/odla/schema.mjs` (a single `notes` entity) and `src/odla/rules.mjs`
313
+ * (deny-all), and creates the `src/odla` and `.odla` directories. Also runs
314
+ * `ensureGitignore` so the local token/credentials paths are ignored.
315
+ *
316
+ * Fully local and synchronous — no network calls. The config file is only
317
+ * written when it doesn't already exist unless `force` is set (otherwise it
318
+ * throws); the schema/rules files are written only when missing (never
319
+ * overwritten, even with `force`). `appId` must match `^[a-z0-9][a-z0-9-]*$` or
320
+ * it throws. Defaults: `envs` → `["dev"]`, `services` → `["db","ai"]`,
321
+ * `aiProvider` → `"anthropic"` (which also picks the `keyEnv`, e.g.
322
+ * `ANTHROPIC_API_KEY`/`OPENAI_API_KEY`/`GOOGLE_API_KEY`).
323
+ *
324
+ * @param options.appId Slug for the app (lowercase alphanumerics and hyphens).
325
+ * @param options.name Human-readable app name embedded in the config.
326
+ * @param options.rootDir Project root (defaults to `process.cwd()`).
327
+ * @param options.configPath Config filename relative to root (default `odla.config.mjs`).
328
+ * @param options.envs Environment names (default `["dev"]`; production is an explicit opt-in).
329
+ * @param options.services Enabled services (default `["db","ai"]`).
330
+ * @param options.aiProvider AI provider slug (default `"anthropic"`).
331
+ * @param options.force Overwrite an existing config file instead of throwing.
332
+ * @param options.stdout Optional console-like sink (defaults to `console`).
333
+ */
181
334
  declare function initProject(options: InitOptions): void;
182
335
 
336
+ interface RunResult {
337
+ code: number;
338
+ stdout: string;
339
+ stderr: string;
340
+ }
341
+ /** Subprocess seam: injectable in tests, `defaultRunner` in production. */
342
+ type CommandRunner = (cmd: string, args: string[], opts?: {
343
+ input?: string;
344
+ cwd?: string;
345
+ }) => Promise<RunResult>;
346
+
183
347
  type OdlaEnvName = string;
184
348
  type AppRules = Record<string, {
185
349
  view?: string;
@@ -192,6 +356,7 @@ interface ClerkAuthConfig {
192
356
  audience?: string;
193
357
  mode?: "client" | "full";
194
358
  }
359
+ /** Authored `odla.config.mjs` contract consumed by doctor and provision. */
195
360
  interface OdlaProjectConfig {
196
361
  platformUrl?: string;
197
362
  dbEndpoint?: string;
@@ -238,6 +403,7 @@ interface OdlaProjectConfig {
238
403
  gitignore?: boolean;
239
404
  };
240
405
  }
406
+ /** Normalized project config with resolved paths, endpoints, envs, and services. */
241
407
  interface LoadedProjectConfig extends OdlaProjectConfig {
242
408
  configPath: string;
243
409
  rootDir: string;
@@ -252,6 +418,7 @@ interface LoadedProjectConfig extends OdlaProjectConfig {
252
418
  gitignore: boolean;
253
419
  };
254
420
  }
421
+ /** Private mode-0600 local state written by provision and never committed. */
255
422
  interface LocalCredentials {
256
423
  appId: string;
257
424
  platformUrl: string;
@@ -263,10 +430,15 @@ interface LocalCredentials {
263
430
  o11yToken?: string;
264
431
  }>;
265
432
  }
433
+ /** Controls one dev-first provisioning run; production mutation requires `yes`. */
266
434
  interface ProvisionOptions {
267
435
  configPath: string;
268
436
  dryRun?: boolean;
269
437
  rotateKeys?: boolean;
438
+ /** Rotate only the o11y ingest token; leaves db keys unchanged. */
439
+ rotateO11yToken?: boolean;
440
+ /** Push configured Worker secrets to every configured env after provisioning. */
441
+ pushSecrets?: boolean;
270
442
  writeCredentials?: boolean;
271
443
  writeDevVars?: string | boolean;
272
444
  token?: string;
@@ -276,10 +448,14 @@ interface ProvisionOptions {
276
448
  interactive?: boolean;
277
449
  /** Test/embedding override for opening the approval URL. Defaults to the OS browser opener. */
278
450
  openApprovalUrl?: (url: string) => Promise<void>;
451
+ /** Explicit consent for a non-dry-run plan containing `prod` or `production`. */
279
452
  yes?: boolean;
280
453
  fetch?: typeof fetch;
454
+ /** Test/embedding override for Wrangler subprocesses used by `pushSecrets`. */
455
+ secretRunner?: CommandRunner;
281
456
  stdout?: Pick<typeof console, "log" | "error">;
282
457
  }
458
+ /** Human-reviewable, secret-free plan printed by `provision({ dryRun: true })`. */
283
459
  interface ProvisionPlan {
284
460
  appId: string;
285
461
  appName: string;
@@ -291,6 +467,7 @@ interface ProvisionPlan {
291
467
  hasRules: boolean;
292
468
  aiProvider?: string;
293
469
  }
470
+ /** Inputs for a read-only live environment smoke check. */
294
471
  interface SmokeOptions {
295
472
  configPath: string;
296
473
  env?: string;
@@ -298,21 +475,50 @@ interface SmokeOptions {
298
475
  stdout?: Pick<typeof console, "log" | "error">;
299
476
  }
300
477
 
478
+ /**
479
+ * Provision an app end-to-end from its config — the primary deploy path, and
480
+ * (apart from key rotation) idempotent, so re-running is safe. Obtains a
481
+ * developer token, creates the registry app when absent, enables each service
482
+ * per env (AI also gets `setAi` with the configured provider/model), configures
483
+ * Clerk auth and links, then per env mints or reuses credentials only for the
484
+ * configured services, pushes the schema with the db key and the
485
+ * rules with the developer token, and stores the provider key in the tenant
486
+ * vault when `ai.keyEnv` is set and present. Finally writes the credentials file
487
+ * (mode 0600, gitignored) and, when requested, `.dev.vars`.
488
+ *
489
+ * The developer token comes from (in order) `options.token`, `$ODLA_DEV_TOKEN`,
490
+ * the cached `.odla` token, or a fresh device handshake — which prints a user
491
+ * code + approval URL and, in interactive terminals, auto-opens the browser
492
+ * (`open: true`/`false` forces/suppresses it). Network error bodies pass through
493
+ * `redactSecrets` before display.
494
+ *
495
+ * @param options.dryRun Print the resolved plan and return before any network call/write.
496
+ * @param options.rotateKeys Rotate db keys and o11y tokens.
497
+ * @param options.rotateO11yToken Rotate only the o11y token.
498
+ * @param options.pushSecrets Preflight Wrangler, then push each env's configured
499
+ * Worker secrets immediately after credential provisioning.
500
+ * @param options.writeDevVars `true`/a path writes `.dev.vars`; `writeCredentials: false` skips the creds file.
501
+ * @param options.yes Required for a non-dry-run plan containing `prod` or
502
+ * `production`; callers must show and review `dryRun` output first.
503
+ * @throws When a production plan is executed without `yes`, configuration is
504
+ * invalid, authorization fails, or a provisioning operation fails.
505
+ */
301
506
  declare function provision(options: ProvisionOptions): Promise<void>;
302
507
 
508
+ /**
509
+ * Return `value` with every secret-shaped substring replaced by a `[redacted]`
510
+ * placeholder that keeps the identifying prefix (e.g. `sk_live_[redacted]`).
511
+ * Matches odla db keys (`odla_sk_`/`odla_dev_`), Clerk secret keys
512
+ * (`sk_live_`/`sk_test_`), OpenAI keys (`sk-`), webhook signing secrets
513
+ * (`whsec_`), o11y tokens (`o11y_`), GitHub tokens (`ghp_`/`gho_`/`github_pat_`),
514
+ * and AWS access-key ids (`AKIA…`). Clerk publishable keys (`pk_test_`/
515
+ * `pk_live_`) are public by design and intentionally left untouched. Used to
516
+ * sanitize anything the CLI echoes (notably network error bodies) before it
517
+ * reaches stdout/stderr. Non-matching input is returned unchanged.
518
+ */
303
519
  declare function redactSecrets(value: string): string;
304
520
 
305
- interface RunResult {
306
- code: number;
307
- stdout: string;
308
- stderr: string;
309
- }
310
- /** Subprocess seam: injectable in tests, `defaultRunner` in production. */
311
- type CommandRunner = (cmd: string, args: string[], opts?: {
312
- input?: string;
313
- cwd?: string;
314
- }) => Promise<RunResult>;
315
-
521
+ /** Moves locally stored configured service credentials to one Wrangler environment over stdin. */
316
522
  interface SecretsPushOptions {
317
523
  configPath: string;
318
524
  env: string;
@@ -323,38 +529,90 @@ interface SecretsPushOptions {
323
529
  stdout?: Pick<typeof console, "log" | "error">;
324
530
  }
325
531
  /**
326
- * Moves the env's odla-db key from `.odla/credentials.local.json` into the
327
- * Worker via `wrangler secret put ODLA_API_KEY`, piping the value over stdin
328
- * so it never appears on argv, in output, or in the conversation transcript.
532
+ * Moves the env's configured db and/or o11y credentials from the private local
533
+ * credentials file into the Worker, piping values over stdin so they never
534
+ * appear on argv, in output, or in the conversation transcript.
329
535
  */
330
536
  declare function secretsPush(options: SecretsPushOptions): Promise<void>;
331
537
 
538
+ /** Agent harnesses with a first-class local adapter. */
539
+ declare const AGENT_HARNESSES: readonly ["claude", "codex", "cursor", "copilot", "gemini", "agents"];
540
+ /** A supported coding-agent harness. `agents` is the portable `AGENTS.md` adapter. */
541
+ type AgentHarness = (typeof AGENT_HARNESSES)[number];
542
+ /** A harness name accepted by setup; `all` expands to every project-local adapter. */
543
+ type AgentHarnessSelector = AgentHarness | "all";
544
+ /** Controls project-local or global installation of the bundled agent runbooks. */
332
545
  interface SkillInstallOptions {
333
- /** Project directory receiving `.claude/skills/`. Defaults to cwd. Ignored with `global`. */
546
+ /** Project directory receiving the shared runbooks and harness adapters. Defaults to cwd. */
334
547
  dir?: string;
335
- /** Install into `~/.claude/skills/` instead of the project. */
548
+ /** Install user-wide Claude and/or Codex skills instead of project adapters. */
336
549
  global?: boolean;
337
- /** Overwrite locally modified skill files. */
550
+ /** Harnesses to install. The programmatic compatibility default is `claude`; the CLI passes `all`. */
551
+ harnesses?: AgentHarnessSelector[];
552
+ /** Overwrite locally modified odla-managed files or managed instruction sections. */
338
553
  force?: boolean;
339
554
  /** Test/embedding override for the home directory. */
340
555
  homeDir?: string;
556
+ /** Test/embedding override for `$CODEX_HOME`. */
557
+ codexHomeDir?: string;
341
558
  /** Test/embedding override for the bundled skills directory. */
342
559
  sourceDir?: string;
343
560
  stdout?: Pick<typeof console, "log" | "error">;
344
561
  }
562
+ /** One harness adapter and the directories or files through which it discovers odla. */
563
+ interface HarnessInstallResult {
564
+ harness: AgentHarness;
565
+ targets: string[];
566
+ }
567
+ /** Files written or left unchanged by an idempotent agent-runbook installation. */
345
568
  interface SkillInstallResult {
569
+ /** Primary native skill directory, retained for compatibility with earlier callers. */
346
570
  targetDir: string;
571
+ /** Files changed directly under `targetDir`, relative to that directory. */
347
572
  written: string[];
573
+ /** Files already current directly under `targetDir`, relative to that directory. */
348
574
  unchanged: string[];
575
+ /** Absolute paths of every changed shared-runbook or adapter file. */
576
+ writtenPaths: string[];
577
+ /** Absolute paths of every already-current shared-runbook or adapter file. */
578
+ unchangedPaths: string[];
579
+ harnesses: HarnessInstallResult[];
349
580
  }
350
581
  /**
351
- * Copies the skills bundled with this package into `.claude/skills/` so the
352
- * user's agent picks them up. Idempotent: unchanged files are skipped, and a
353
- * locally modified file is never overwritten without `force`.
582
+ * Installs one shared offline runbook tree plus thin native adapters for the
583
+ * selected coding-agent harnesses. Project installs use `.agents/skills/` as
584
+ * the canonical bundle; Claude Code, Cursor, Copilot, Gemini, and generic
585
+ * `AGENTS.md` adapters point to it. Global installs support the native Claude
586
+ * and Codex skill roots only.
587
+ *
588
+ * Installation is idempotent and planned before any write: an odla-managed
589
+ * file changed by the user aborts the whole operation unless `force` is set.
590
+ * Existing `AGENTS.md`, `GEMINI.md`, and Copilot instructions are preserved;
591
+ * only the bounded odla-managed section is appended or replaced.
354
592
  */
355
593
  declare function installSkill(options?: SkillInstallOptions): SkillInstallResult;
356
594
 
595
+ /**
596
+ * Verify a live, already-provisioned environment end-to-end. Resolves the target
597
+ * env (`options.env`, else `dev`, else the first declared env) and requires it to
598
+ * be declared in the config. Reads the local credentials file and checks that it
599
+ * belongs to this app and holds a `tenantId` + `dbKey` for the env — otherwise it
600
+ * throws pointing the user at `odla-ai provision --write-dev-vars`.
601
+ *
602
+ * It then makes real network calls: fetches the registry public-config (and, when
603
+ * `ai.provider` is configured, asserts the live provider matches), fetches the
604
+ * live db schema with the db key and asserts every entity from the local schema
605
+ * is present, and runs a `count` aggregate against the first entity to confirm
606
+ * the db answers queries. Progress lines are printed and it ends with `ok`.
607
+ * Read-only — it writes nothing and throws on the first mismatch or failed
608
+ * request.
609
+ *
610
+ * @param options.configPath Path to the `odla.config.mjs`.
611
+ * @param options.env Env to check (default `dev`, else the first declared env).
612
+ * @param options.fetch Injectable `fetch` (for tests/embedding).
613
+ * @param options.stdout Optional console-like sink (defaults to `console`).
614
+ */
357
615
  declare function smoke(options: SmokeOptions): Promise<void>;
358
616
 
359
- export { type LoadedProjectConfig, type LocalCredentials, type OdlaProjectConfig, type ProvisionOptions, type ProvisionPlan, type SecretsPushOptions, type SkillInstallOptions, type SkillInstallResult, type SmokeOptions, doctor, initProject, installSkill, provision, redactSecrets, runCli, secretsPush, smoke };
617
+ export { AGENT_HARNESSES, type AgentHarness, type AgentHarnessSelector, CAPABILITIES, type HarnessInstallResult, type LoadedProjectConfig, type LocalCredentials, type OdlaProjectConfig, type ProvisionOptions, type ProvisionPlan, type SecretsPushOptions, type SkillInstallOptions, type SkillInstallResult, type SmokeOptions, doctor, initProject, installSkill, printCapabilities, provision, redactSecrets, runCli, secretsPush, smoke };
360
618
  ```
package/package.json CHANGED
@@ -1,11 +1,17 @@
1
1
  {
2
2
  "name": "@odla-ai/cli",
3
- "version": "0.4.0",
4
- "description": "Project-neutral CLI for provisioning odla apps, database schemas, AI settings, and local runtime files.",
3
+ "version": "0.5.0",
4
+ "description": "Agent-operable CLI for provisioning odla apps, services, credentials, Worker secrets, and local runtime files.",
5
5
  "license": "MIT",
6
+ "homepage": "https://odla.ai/docs/packages/cli",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/cory/odla-ai.git",
10
+ "directory": "packages/cli"
11
+ },
6
12
  "type": "module",
7
13
  "bin": {
8
- "odla-ai": "./dist/bin.js"
14
+ "odla-ai": "dist/bin.js"
9
15
  },
10
16
  "main": "./dist/index.cjs",
11
17
  "module": "./dist/index.js",
@@ -29,7 +35,8 @@
29
35
  "node": ">=20"
30
36
  },
31
37
  "publishConfig": {
32
- "access": "public"
38
+ "access": "public",
39
+ "provenance": false
33
40
  },
34
41
  "keywords": [
35
42
  "odla",
@@ -38,6 +45,7 @@
38
45
  "provisioning",
39
46
  "cloudflare",
40
47
  "database",
48
+ "observability",
41
49
  "knowledge-graph",
42
50
  "ai"
43
51
  ],
@@ -51,9 +59,9 @@
51
59
  "prepublishOnly": "npm run build && npm run gen:llms"
52
60
  },
53
61
  "dependencies": {
54
- "@odla-ai/ai": "^0.2.1",
62
+ "@odla-ai/ai": "^0.3.0",
55
63
  "@odla-ai/apps": "^0.7.1",
56
- "@odla-ai/db": "^0.5.0"
64
+ "@odla-ai/db": "^0.6.0"
57
65
  },
58
66
  "devDependencies": {
59
67
  "@types/node": "^22.10.0",