@odla-ai/cli 0.22.0 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -11
- package/dist/bin.cjs +8 -6
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-DINDRUDA.js → chunk-RZDRUVBT.js} +9 -7
- package/dist/{chunk-DINDRUDA.js.map → chunk-RZDRUVBT.js.map} +1 -1
- package/dist/index.cjs +8 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/skills/odla/SKILL.md +8 -2
- package/skills/odla/references/build.md +6 -5
- package/skills/odla/references/pm.md +18 -4
- package/skills/odla/references/sdks.md +5 -5
- package/skills/odla-migrate/SKILL.md +10 -4
- package/skills/odla-migrate/references/phase-0-preflight.md +7 -4
- package/skills/odla-migrate/references/phase-1-static.md +3 -1
- package/skills/odla-migrate/references/phase-2-chapter.md +12 -0
- package/skills/odla-migrate/references/phase-2-db.md +11 -3
- package/skills/odla-migrate/references/phase-2b-calendar.md +6 -5
- package/skills/odla-migrate/references/phase-3-auth.md +15 -1
- package/skills/odla-migrate/references/phase-4-ai.md +2 -1
- package/skills/odla-migrate/references/phase-5-cutover.md +11 -9
- package/skills/odla-migrate/references/project-state.md +80 -0
package/README.md
CHANGED
|
@@ -37,6 +37,26 @@ npx @odla-ai/cli runbook list # what exists
|
|
|
37
37
|
Reading works for any signed-in developer and needs no `odla.config.mjs` — the
|
|
38
38
|
advice is most useful before there is a project.
|
|
39
39
|
|
|
40
|
+
Runbooks tell an agent how to operate; PM tells every agent what this project is
|
|
41
|
+
trying to prove, what is active, what was decided, and what is broken. Once the
|
|
42
|
+
app is registered, start each session by reading its doing tasks, open bugs and
|
|
43
|
+
goals, and recent decisions:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npx odla-ai pm task list --app <appId> --column doing
|
|
47
|
+
npx odla-ai pm bug list --app <appId> --status open
|
|
48
|
+
npx odla-ai pm goal list --app <appId> --status open
|
|
49
|
+
npx odla-ai pm decision list --app <appId> --limit 20
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Read the active task, linked goal, and comments before changing code. Without
|
|
53
|
+
`--app`, list commands span every project the account co-owns, which is the
|
|
54
|
+
right first view when coordinating several efforts; scope every write to the
|
|
55
|
+
exact `appId` from that project's config. PM requires a registered app. Before
|
|
56
|
+
the first provision, use a focused commit/checkpoint, then initialize PM and
|
|
57
|
+
backfill that evidence immediately after registration. Never use a parallel
|
|
58
|
+
status diary or put a secret in PM.
|
|
59
|
+
|
|
40
60
|
**Runbooks are procedure; JSDoc is API.** What a function takes, returns, and
|
|
41
61
|
guarantees is documented on the export itself, ships in the installed
|
|
42
62
|
`.d.ts`, and renders per package at <https://odla.ai/docs>. A runbook will tell
|
|
@@ -93,11 +113,14 @@ npx @odla-ai/cli init --app-id my-app --name "My App"
|
|
|
93
113
|
```
|
|
94
114
|
|
|
95
115
|
For a project you keep working in, install it as a dev dependency so the
|
|
96
|
-
shorter `npx odla-ai` form works
|
|
116
|
+
shorter `npx odla-ai` form works. ODLA is under active development: use a normal
|
|
117
|
+
dependency declaration, commit the lockfile, and let `npm ci` reproduce the
|
|
118
|
+
resolved graph:
|
|
97
119
|
|
|
98
120
|
```bash
|
|
99
|
-
npm view @odla-ai/cli
|
|
100
|
-
npm i -D
|
|
121
|
+
npm view @odla-ai/cli version
|
|
122
|
+
npm i -D @odla-ai/cli
|
|
123
|
+
npm ls @odla-ai/cli
|
|
101
124
|
```
|
|
102
125
|
|
|
103
126
|
## Prerequisites
|
|
@@ -360,8 +383,8 @@ rolling-window/age-out, quota-backoff, retention/purge, or provider-derived
|
|
|
360
383
|
mutation-id control. Public health remains aggregate rather than per calendar.
|
|
361
384
|
|
|
362
385
|
The bundled build/migration skills add a passive pre-ship gate with
|
|
363
|
-
`@odla-ai/security`:
|
|
364
|
-
`npm i -D
|
|
386
|
+
`@odla-ai/security`: install it with a normal development range, commit the
|
|
387
|
+
lockfile, then run `npm i -D @odla-ai/security`, followed by
|
|
365
388
|
`npx odla-security scan . --profile odla --out .odla/security/pre-ship --fail-on high --fail-on-candidates critical`.
|
|
366
389
|
The passive scan remains a separate binary: it makes no model calls and does
|
|
367
390
|
not execute target code. After explicit redacted-source approval,
|
|
@@ -385,12 +408,11 @@ a conservative `Retry-After`. A provider-side `429` uses the sanitized
|
|
|
385
408
|
carries a bounded `Retry-After` only when the upstream supplied one. The CLI
|
|
386
409
|
does not echo arbitrary response text or silently change the admin-selected
|
|
387
410
|
model.
|
|
388
|
-
|
|
389
|
-
`npm
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
should use the published `odla-security` command above.
|
|
411
|
+
Confirm `npm view @odla-ai/security version` succeeds and record the installed
|
|
412
|
+
version from `npm ls @odla-ai/security` with the scan evidence. A registry
|
|
413
|
+
failure blocks the preflight; it is not a clean scan. odla's own engineering
|
|
414
|
+
environment uses an equivalent internal gate; customer projects should use the
|
|
415
|
+
published `odla-security` command above.
|
|
394
416
|
|
|
395
417
|
For a server-side, commit-pinned review, connect one repository through the
|
|
396
418
|
source-read-only odla GitHub App. The CLI infers `owner/name` from a safe GitHub HTTPS
|
package/dist/bin.cjs
CHANGED
|
@@ -1390,6 +1390,7 @@ function chooseIdMode(options, rows) {
|
|
|
1390
1390
|
async function appImport(options) {
|
|
1391
1391
|
const cfg = await loadProjectConfig(options.configPath);
|
|
1392
1392
|
const out = options.stdout ?? console;
|
|
1393
|
+
const say = options.json ? (line) => out.error(line) : (line) => out.log(line);
|
|
1393
1394
|
const doFetch = options.fetch ?? fetch;
|
|
1394
1395
|
const { tenant } = resolveTenant(cfg, options.env);
|
|
1395
1396
|
const text = options.file === "-" ? (options.readStdin ?? (() => (0, import_node_fs6.readFileSync)(0, "utf8")))() : (0, import_node_fs6.readFileSync)(options.file, "utf8");
|
|
@@ -1411,10 +1412,10 @@ ${detail}${more}`);
|
|
|
1411
1412
|
}
|
|
1412
1413
|
const chunks = (0, import_import.planImportChunks)(ops);
|
|
1413
1414
|
const result = { tenant, rows: ops.length, chunks: chunks.length, committed: 0, duplicate: 0, txIds: [], ignored };
|
|
1414
|
-
if (ignored.length > 0)
|
|
1415
|
+
if (ignored.length > 0) say(`ignoring server-maintained field(s): ${ignored.join(", ")} \u2014 odla-db stamps these on write`);
|
|
1415
1416
|
if (options.dryRun || options.yes !== true) {
|
|
1416
1417
|
const why = options.dryRun ? "--dry-run" : "no --yes";
|
|
1417
|
-
|
|
1418
|
+
say(`${tenant}: would upsert ${ops.length} row(s) across ${chunks.length} transaction(s) \u2014 nothing written (${why})`);
|
|
1418
1419
|
if (options.json) out.log(JSON.stringify(result, null, 2));
|
|
1419
1420
|
return result;
|
|
1420
1421
|
}
|
|
@@ -1623,6 +1624,7 @@ function printPlan(out, verb, pre, opts) {
|
|
|
1623
1624
|
async function appTransfer(options) {
|
|
1624
1625
|
const cfg = await loadProjectConfig(options.configPath);
|
|
1625
1626
|
const out = options.stdout ?? console;
|
|
1627
|
+
const say = options.json ? (line) => out.error(line) : (line) => out.log(line);
|
|
1626
1628
|
const doFetch = options.fetch ?? fetch;
|
|
1627
1629
|
const tenants = bothTenants(cfg);
|
|
1628
1630
|
const route2 = endpointsFor(options.verb, tenants);
|
|
@@ -1643,7 +1645,7 @@ async function appTransfer(options) {
|
|
|
1643
1645
|
throw new Error(`pre-flight failed${pre.body.error?.code ? ` (${pre.body.error.code})` : ""}: ${pre.body.error?.message ?? pre.status}`);
|
|
1644
1646
|
}
|
|
1645
1647
|
const plan = pre.body;
|
|
1646
|
-
printPlan(
|
|
1648
|
+
printPlan({ log: say }, options.verb, plan, options);
|
|
1647
1649
|
if (options.verb === "go-live" && !plan.targetEmpty) {
|
|
1648
1650
|
throw new Error(
|
|
1649
1651
|
`${route2.target} already has data \u2014 go-live has already happened. Use \`odla-ai app promote --yes\` to push schema and rules, or \`odla-ai app refresh-sandbox --yes\` to pull live back down.`
|
|
@@ -1651,7 +1653,7 @@ async function appTransfer(options) {
|
|
|
1651
1653
|
}
|
|
1652
1654
|
if (plan.blockers.length > 0) throw new Error(`cannot ${options.verb}: ${plan.blockers.map((b) => b.message).join("; ")}`);
|
|
1653
1655
|
if (options.dryRun || options.yes !== true) {
|
|
1654
|
-
|
|
1656
|
+
say(`nothing written (${options.dryRun ? "--dry-run" : "no --yes"})`);
|
|
1655
1657
|
if (options.json) out.log(JSON.stringify(plan, null, 2));
|
|
1656
1658
|
return { ok: true, plan };
|
|
1657
1659
|
}
|
|
@@ -1665,7 +1667,7 @@ async function appTransfer(options) {
|
|
|
1665
1667
|
);
|
|
1666
1668
|
if (res2.status !== 200) throw new Error(`promote failed${res2.body.error?.code ? ` (${res2.body.error.code})` : ""}: ${res2.body.error?.message ?? res2.status}`);
|
|
1667
1669
|
if (options.json) out.log(JSON.stringify(res2.body, null, 2));
|
|
1668
|
-
else
|
|
1670
|
+
else say(`${route2.target}: promoted ${(res2.body.applied ?? []).join(", ")}`);
|
|
1669
1671
|
return { ok: true, plan, result: res2.body };
|
|
1670
1672
|
}
|
|
1671
1673
|
const res = await api(
|
|
@@ -1684,7 +1686,7 @@ async function appTransfer(options) {
|
|
|
1684
1686
|
doFetch
|
|
1685
1687
|
);
|
|
1686
1688
|
if (res.status !== 200) throw new Error(`${options.verb} failed${res.body.error?.code ? ` (${res.body.error.code})` : ""}: ${res.body.error?.message ?? res.status}`);
|
|
1687
|
-
|
|
1689
|
+
say(`${route2.target}: replaced from ${route2.source} (tx ${res.body.destination?.maxTx}, epoch ${res.body.destination?.epoch}) \u2014 connected clients resync automatically`);
|
|
1688
1690
|
if (options.includeFiles) await copyFiles(cfg, token, route2, doFetch, out);
|
|
1689
1691
|
if (options.json) out.log(JSON.stringify(res.body, null, 2));
|
|
1690
1692
|
return { ok: true, plan, result: res.body };
|