@odla-ai/cli 0.38.3 → 0.40.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/bin.cjs +724 -293
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-WJAN5CZ2.js → chunk-2IHE5U3M.js} +596 -215
- package/dist/chunk-2IHE5U3M.js.map +1 -0
- package/dist/{cli-A5R2DMM4.js → cli-LRJBESE6.js} +2 -2
- package/dist/index.cjs +630 -254
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +2 -2
- package/skills/odla/SKILL.md +51 -11
- package/skills/odla/references/agent-identity.md +94 -111
- package/dist/chunk-WJAN5CZ2.js.map +0 -1
- /package/dist/{cli-A5R2DMM4.js.map → cli-LRJBESE6.js.map} +0 -0
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@odla-ai/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.40.0",
|
|
4
4
|
"description": "Agent-operable CLI for odla provisioning, calendar consent and connection lifecycle, System AI administration, Worker secrets, security jobs, and smoke checks.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://odla.ai/docs/packages/cli",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"@odla-ai/ai": "0.15.0",
|
|
62
62
|
"@odla-ai/apps": "0.12.0",
|
|
63
63
|
"@odla-ai/brand": "0.6.0",
|
|
64
|
-
"@odla-ai/db": "0.
|
|
64
|
+
"@odla-ai/db": "0.12.0",
|
|
65
65
|
"@odla-ai/security": "0.3.3"
|
|
66
66
|
},
|
|
67
67
|
"devDependencies": {
|
package/skills/odla/SKILL.md
CHANGED
|
@@ -36,9 +36,12 @@ State which path you're taking and what you'll build in one line; get a nod.
|
|
|
36
36
|
|
|
37
37
|
## Non-negotiable rules
|
|
38
38
|
|
|
39
|
-
1. **Never print, paste, or commit a secret.** Never `cat` `.dev.vars
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
1. **Never print, paste, or commit a secret.** Never `cat` `.dev.vars` or
|
|
40
|
+
anything under `~/.odla` (`device.json`, `session.json`,
|
|
41
|
+
`apps/<appId>/credentials.json`, `admin-token.local.json`) — use `ls -l` to
|
|
42
|
+
confirm they exist (and are `0600`). Credentials live per machine, under
|
|
43
|
+
`~/.odla`, not per checkout; a repository copy from an older CLI is moved
|
|
44
|
+
there automatically on first run. The only value a human ever pastes is a
|
|
42
45
|
Clerk **publishable** key (`pk_…`) — public by design.
|
|
43
46
|
A fresh odla device request also needs the existing account email via
|
|
44
47
|
`--email` or `ODLA_USER_EMAIL`; email is a non-secret identifier. Never ask
|
|
@@ -49,9 +52,9 @@ State which path you're taking and what you'll build in one line; get a nod.
|
|
|
49
52
|
registry matches the exact string. An address that is not a registered
|
|
50
53
|
account does NOT error: it mints an indistinguishable decoy, so the CLI
|
|
51
54
|
prints a normal approval URL that can never be approved by anyone. Ask the
|
|
52
|
-
human
|
|
53
|
-
|
|
54
|
-
|
|
55
|
+
human — once. The CLI records the account an approval actually succeeded for
|
|
56
|
+
in `~/.odla/identity.json`, so later commands on this machine need no
|
|
57
|
+
`--email` at all. Current clients never persist pending device codes.
|
|
55
58
|
2. **Sandbox before live.** Every app has two databases on production odla.ai:
|
|
56
59
|
a sandbox (env `dev`, tenant `<appId>--dev`) and a live one (env `prod`,
|
|
57
60
|
tenant `<appId>`). "prod" names the app's live DATABASE, never a different
|
|
@@ -71,10 +74,43 @@ State which path you're taking and what you'll build in one line; get a nod.
|
|
|
71
74
|
platform/Google consent URL returned by odla; booking runs server-side
|
|
72
75
|
through the SDK with the app's existing key, never from a browser.
|
|
73
76
|
|
|
74
|
-
##
|
|
77
|
+
## Enrol the machine once. Then stop asking.
|
|
75
78
|
|
|
76
|
-
|
|
77
|
-
|
|
79
|
+
**This is step zero, and it is one command.** Run it before anything else that
|
|
80
|
+
touches odla:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
npx --yes @odla-ai/cli@latest device enroll --no-open --wait 600
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
One browser approval, and no flags to remember. After it, every worktree on
|
|
87
|
+
this machine mints its own short-lived credentials with nobody's attention, for
|
|
88
|
+
every app the approver owns — including apps created later — carrying every
|
|
89
|
+
capability that approval was allowed to carry. Narrowing is deliberate:
|
|
90
|
+
`--app <id>` or `--capability <c>`, and the CLI says what that gave up. The deadline is a **gap, not a clock**: each use rolls it
|
|
91
|
+
forward, so continuous work never interrupts anyone.
|
|
92
|
+
|
|
93
|
+
A platform administrator can do the same across all of odla:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
npx --yes @odla-ai/cli@latest device enroll --platform-wide --device-ttl 6w --no-open --wait 600
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Check what this machine already holds before asking anyone for anything:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
npx --yes @odla-ai/cli@latest whoami # what it holds, and when it lapses
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Do **not** ask for capabilities one at a time, and do not re-enrol per worktree.
|
|
106
|
+
Both were the old shape and both mean interrupting a human who is usually not
|
|
107
|
+
there. If a command still starts a handshake, the CLI prints why and prints the
|
|
108
|
+
enrollment line that ends it — run that instead of approving repeatedly.
|
|
109
|
+
|
|
110
|
+
## The approval itself
|
|
111
|
+
|
|
112
|
+
Whichever command needs it, the handshake protocol is the same. Start it as one
|
|
113
|
+
foreground tool process with browser auto-launch suppressed:
|
|
78
114
|
|
|
79
115
|
```bash
|
|
80
116
|
npx --yes @odla-ai/cli@latest auth login --app <appId> --email <odla-account> --no-open --wait 600
|
|
@@ -88,8 +124,12 @@ the OS `open` command, use browser control, curl a handshake endpoint, create a
|
|
|
88
124
|
shell polling/wait loop, detach the process, or start a substitute handshake.
|
|
89
125
|
The device code exists only in the running CLI. If it exits 75, the old request
|
|
90
126
|
cannot be collected; start one fresh foreground invocation and surface only its
|
|
91
|
-
new URL.
|
|
92
|
-
|
|
127
|
+
new URL.
|
|
128
|
+
|
|
129
|
+
Enrollment is the only human decision the CLI can obtain. Revoking a machine,
|
|
130
|
+
purging an app, transferring ownership, and rotating credentials still need a
|
|
131
|
+
signed-in human in Studio — no machine credential can do them, however wide its
|
|
132
|
+
approval was.
|
|
93
133
|
|
|
94
134
|
## Tooling sources
|
|
95
135
|
|
|
@@ -1,132 +1,115 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Keep one identity across worktrees, projects, and days
|
|
2
2
|
|
|
3
|
-
Use this
|
|
4
|
-
|
|
5
|
-
checkout that first obtained the credential.
|
|
3
|
+
Use this when an agent must keep the same attributable identity while working in
|
|
4
|
+
more than one checkout, or across the expiry of a short-lived credential.
|
|
6
5
|
|
|
7
|
-
##
|
|
6
|
+
## The short version
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
or `release-reviewer`. The Registry places it under the approving human's
|
|
12
|
-
verified namespace (for example, `@cory/customer-app`). The CLI derives this
|
|
13
|
-
suffix deterministically from the exact project; SDK callers may explicitly
|
|
14
|
-
request a different stable `agentHandle` for a cross-project agent.
|
|
15
|
-
- No token, credential file, or browser session is copied between worktrees,
|
|
16
|
-
machines, people, or chat messages.
|
|
8
|
+
Enrol the machine once. Nothing else on this page is required for the ordinary
|
|
9
|
+
case:
|
|
17
10
|
|
|
18
|
-
|
|
11
|
+
```cmd
|
|
12
|
+
npx --yes @odla-ai/cli@latest device enroll --no-open --wait 600
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
One human approval binds THIS machine. From then on every worktree on it mints
|
|
16
|
+
its own short-lived sessions with no browser, for every app the approver owns —
|
|
17
|
+
including apps created afterwards — carrying every capability that approval was
|
|
18
|
+
allowed to carry. The credential's deadline measures **silence**: each use rolls
|
|
19
|
+
it forward, so an agent that keeps working never has to interrupt anyone.
|
|
19
20
|
|
|
20
21
|
```cmd
|
|
21
|
-
npx --yes @odla-ai/cli@latest
|
|
22
|
-
npx --yes @odla-ai/cli@latest
|
|
22
|
+
npx --yes @odla-ai/cli@latest whoami # what this machine holds, and when it lapses
|
|
23
|
+
npx --yes @odla-ai/cli@latest device list # every machine you have enrolled
|
|
23
24
|
```
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
cache lives under `~/.odla/profiles/delivery/`, independently of any repository
|
|
27
|
-
or linked worktree. Select it explicitly with `--context delivery` or
|
|
28
|
-
`ODLA_CONTEXT=delivery`; there is no ambient current context.
|
|
26
|
+
## Where state lives
|
|
29
27
|
|
|
30
|
-
|
|
28
|
+
Per machine, under `~/.odla`, never per checkout:
|
|
31
29
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
| file | what it is |
|
|
31
|
+
|---|---|
|
|
32
|
+
| `device.json` | the durable enrollment secret. Never printed, never copied |
|
|
33
|
+
| `session.json` | the short-lived session minted from it, reused until it lapses |
|
|
34
|
+
| `identity.json` | the odla account an approval succeeded for — so no command has to ask again |
|
|
35
|
+
| `apps/<appId>/dev-token.json` | that app's cached developer credential |
|
|
36
|
+
| `apps/<appId>/credentials.json` | that app's local service credentials |
|
|
37
|
+
| `admin-token.local.json` | scoped capability grants, one file for the machine |
|
|
38
|
+
| `pm-context.json` | the PM project selected by `pm project use` |
|
|
39
|
+
| `profiles/<name>/` | the same, isolated per named operator context |
|
|
35
40
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
41
|
+
A repository `.odla/` cache written by an older CLI is moved here on first run
|
|
42
|
+
and the old copy removed; the CLI says so on stderr. `.dev.vars` stays in the
|
|
43
|
+
checkout — it is a Worker's file, not a credential of yours.
|
|
44
|
+
|
|
45
|
+
`ODLA_HOME` relocates the whole store. The per-file `ODLA_DEVICE_CREDENTIAL`,
|
|
46
|
+
`ODLA_DEV_TOKEN_FILE`, `ODLA_ADMIN_TOKEN_FILE`, and `ODLA_CONTEXT_FILE`
|
|
47
|
+
overrides still win where they are read.
|
|
48
|
+
|
|
49
|
+
## Preconditions for the approval
|
|
50
|
+
|
|
51
|
+
- The human approving owns or co-owns everything the request covers. `--all-apps`
|
|
52
|
+
is not platform-wide authority: the registry resolves it against that human's
|
|
53
|
+
live owned apps at every request, so an app transferred away stops being
|
|
54
|
+
reachable and one created tomorrow is already covered.
|
|
55
|
+
- `--email` is the signed-in **odla account**, never git or GitHub identity. An
|
|
56
|
+
address that is not a registered account does not error — it mints an
|
|
57
|
+
indistinguishable decoy whose approval URL nobody can approve. Ask the human,
|
|
58
|
+
or let `~/.odla/identity.json` answer.
|
|
59
|
+
- No token, credential file, or browser session is ever copied between
|
|
60
|
+
worktrees, machines, people, or chat messages.
|
|
39
61
|
|
|
40
|
-
|
|
41
|
-
The request is immutable: approval cannot edit its identity or grants. The
|
|
42
|
-
handle—not the request label or local context name—is the durable agent identity
|
|
43
|
-
key. Record the full verified handle in the agent handoff; never record the
|
|
44
|
-
token. A normal CLI handshake derives the same handle from the configured
|
|
45
|
-
project in every checkout and worktree.
|
|
62
|
+
## Named contexts, for operators outside a checkout
|
|
46
63
|
|
|
47
|
-
|
|
64
|
+
A named context isolates scope metadata and credential caches — useful when one
|
|
65
|
+
machine acts for more than one platform or account, not for ordinary worktrees:
|
|
48
66
|
|
|
49
67
|
```cmd
|
|
68
|
+
npx --yes @odla-ai/cli@latest context save delivery --platform https://odla.ai --app <appId> --env prod
|
|
50
69
|
npx --yes @odla-ai/cli@latest whoami --context delivery --json
|
|
51
|
-
npx --yes @odla-ai/cli@latest pm next --context delivery --json
|
|
52
70
|
```
|
|
53
71
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
##
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
3.
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
next` and claim the current Ready task revision, while leaving Ready approval to
|
|
84
|
-
a human owner or explicit planner. Identity continuity alone does not preserve
|
|
85
|
-
a stale claim or imply authority outside the newly reviewed grants.
|
|
86
|
-
|
|
87
|
-
## 4. Review remaining credentials
|
|
88
|
-
|
|
89
|
-
Successful collection automatically retires the preceding collected ordinary
|
|
90
|
-
handshake credential for that principal. Verify the old row in Studio's
|
|
91
|
-
agent-credential inventory has a `system:handshake-reconnect:<handshake-id>`
|
|
92
|
-
revocation reason. Do not delete a local cache as a substitute for this
|
|
93
|
-
server-side evidence.
|
|
94
|
-
|
|
95
|
-
The rotation set deliberately excludes manually minted credentials and
|
|
96
|
-
separately scoped handshakes: those may represent another deliberate runtime,
|
|
97
|
-
not a stale copy of this context. Review and revoke them explicitly when they
|
|
98
|
-
are no longer intended.
|
|
99
|
-
|
|
100
|
-
Project grants are still time-bounded. Collection makes the newly reviewed
|
|
101
|
-
selection authoritative for the principal: selected projects receive new
|
|
102
|
-
revisions and every live manager-issued project omitted from that selection is
|
|
103
|
-
revoked. There is not yet a non-interactive `auth rotate` command or OS
|
|
104
|
-
credential-store integration. The named context plus stable handle solves
|
|
105
|
-
worktree/project portability and principal continuity, but it is not ambient or
|
|
106
|
-
permanent authority.
|
|
72
|
+
It stores platform/app/environment metadata only, never credentials, under
|
|
73
|
+
`~/.odla/profiles/delivery/`. Select it explicitly with `--context delivery` or
|
|
74
|
+
`ODLA_CONTEXT`; there is no ambient current context.
|
|
75
|
+
|
|
76
|
+
## When a human is asked again
|
|
77
|
+
|
|
78
|
+
Three cases, and only three:
|
|
79
|
+
|
|
80
|
+
1. **The machine has never been enrolled.** Run the enrollment above.
|
|
81
|
+
2. **The machine lapsed.** It went unused for longer than its window. This is
|
|
82
|
+
the one deliberate interruption in the design — the platform's guaranteed
|
|
83
|
+
moment to tell the human what changed since they last looked. Re-enrol.
|
|
84
|
+
3. **The command needs something the approval did not carry.** A platform scope
|
|
85
|
+
on an owner's enrollment, most often. The CLI says which scope and prints the
|
|
86
|
+
enrollment line that would carry it; an administrator's approval is required
|
|
87
|
+
for `--platform-wide`.
|
|
88
|
+
|
|
89
|
+
Anything else asking repeatedly is a defect — file it with `odla-ai bug report`
|
|
90
|
+
rather than approving on a loop.
|
|
91
|
+
|
|
92
|
+
## What enrollment still cannot do
|
|
93
|
+
|
|
94
|
+
Revoking a machine, permanently deleting an app, transferring ownership, and
|
|
95
|
+
rotating credentials require a signed-in human in Studio. No machine credential
|
|
96
|
+
performs them however wide its approval was, and no flag widens that.
|
|
97
|
+
|
|
98
|
+
Ordinary reviewed access includes `pm.execute` but not `pm.plan`: re-read `pm
|
|
99
|
+
next` and claim the current Ready task revision, leaving Ready approval to a
|
|
100
|
+
human owner or explicit planner.
|
|
107
101
|
|
|
108
102
|
## Recovery and audit evidence
|
|
109
103
|
|
|
110
|
-
-
|
|
111
|
-
|
|
112
|
-
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
the credential
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
project outcome. Preserve the code and pending state, report the incident,
|
|
123
|
-
and retry the same request after Registry is healthy.
|
|
124
|
-
- Project ownership/lifecycle changed after approval: collection expires the
|
|
125
|
-
unusable replacement while preserving the current credential and grant set.
|
|
126
|
-
Restore the intended project state, then start and review a fresh handshake.
|
|
127
|
-
- Lost local cache: save/select the same non-secret context, complete a new
|
|
128
|
-
handshake with the same handle, verify `whoami`, then revoke the lost
|
|
129
|
-
credential from Studio.
|
|
130
|
-
|
|
131
|
-
Audit evidence is the stable principal id/handle, the new credential id, and the
|
|
132
|
-
monotonic project-grant revision shown by Registry—not possession of a token.
|
|
104
|
+
- **`handshake_pending`**: approve the existing code and rerun the same command;
|
|
105
|
+
never create a substitute request.
|
|
106
|
+
- **Exit 75**: the wait cap elapsed with the handshake still approvable. Rerun
|
|
107
|
+
it; the old code cannot be collected and a new one is issued.
|
|
108
|
+
- **A revoked or lapsed machine**: `whoami` says so. Re-enrol; do not delete a
|
|
109
|
+
local file as a substitute for revoking server-side.
|
|
110
|
+
- **Lost `~/.odla`**: re-enrol, verify `whoami`, then revoke the old machine in
|
|
111
|
+
Studio — the credential it holds is still live until you do.
|
|
112
|
+
|
|
113
|
+
Audit evidence is the stable principal id and handle, the device id shown by
|
|
114
|
+
`device list`, and the grant revision Registry reports — never possession of a
|
|
115
|
+
token.
|