@odla-ai/cli 0.17.1 → 0.19.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 +88 -14
- package/dist/bin.cjs +6616 -5127
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-2UKO2NED.js → chunk-QMA5OGKQ.js} +6508 -5005
- package/dist/chunk-QMA5OGKQ.js.map +1 -0
- package/dist/index.cjs +6641 -5133
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +55 -3
- package/dist/index.d.ts +55 -3
- package/dist/index.js +13 -3
- package/dist/runtime/pi-agent.js +22417 -38138
- package/package.json +1 -1
- package/skills/odla/SKILL.md +114 -0
- package/skills/odla/references/pm.md +109 -0
- package/skills/odla/references/sdks.md +8 -5
- package/skills/odla-migrate/SKILL.md +4 -1
- package/skills/odla-migrate/references/phase-2-chapter.md +17 -6
- package/skills/odla-migrate/references/phase-2b-calendar.md +4 -4
- package/skills/odla-migrate/references/phase-3-auth.md +2 -2
- package/skills/odla-migrate/references/troubleshooting.md +23 -0
- package/skills/odla-o11y-debug/SKILL.md +14 -0
- package/dist/chunk-2UKO2NED.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@odla-ai/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.0",
|
|
4
4
|
"description": "Agent-operable CLI for odla provisioning, calendar consent and sync lifecycle, System AI administration, Worker secrets, security jobs, and smoke checks.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://odla.ai/docs/packages/cli",
|
package/skills/odla/SKILL.md
CHANGED
|
@@ -9,6 +9,7 @@ description: >
|
|
|
9
9
|
runbookOrder:
|
|
10
10
|
- references/build.md
|
|
11
11
|
- references/sdks.md
|
|
12
|
+
- references/pm.md
|
|
12
13
|
- references/co-owners.md
|
|
13
14
|
---
|
|
14
15
|
|
|
@@ -41,6 +42,13 @@ State which path you're taking and what you'll build in one line; get a nod.
|
|
|
41
42
|
A fresh odla device request also needs the existing account email via
|
|
42
43
|
`--email` or `ODLA_USER_EMAIL`; email is a non-secret identifier. Never ask
|
|
43
44
|
for an odla password, Clerk token, or browser session.
|
|
45
|
+
**That is the human's odla ACCOUNT email — never infer it from `git config
|
|
46
|
+
user.email`, `gh`, or a commit author.** A git identity is frequently a
|
|
47
|
+
different address (a `+alias`, a `users.noreply.github.com`), and the
|
|
48
|
+
registry matches the exact string. An address that is not a registered
|
|
49
|
+
account does NOT error: it mints an indistinguishable decoy, so the CLI
|
|
50
|
+
prints a normal approval URL that can never be approved by anyone. Ask the
|
|
51
|
+
human, or reuse the address already in `.odla/handshake.local.json`.
|
|
44
52
|
2. **Sandbox before live.** Every app has two databases on production odla.ai:
|
|
45
53
|
a sandbox (env `dev`, tenant `<appId>--dev`) and a live one (env `prod`,
|
|
46
54
|
tenant `<appId>`). "prod" names the app's live DATABASE, never a different
|
|
@@ -129,6 +137,109 @@ guessing which platform/credential steps need manual work. Then:
|
|
|
129
137
|
show the human, then `npx @odla-ai/cli provision --yes --push-secrets` and
|
|
130
138
|
`npx wrangler deploy`.
|
|
131
139
|
|
|
140
|
+
## Track the work in PM, as you go
|
|
141
|
+
|
|
142
|
+
odla has a project manager for agents — conformance goals, a kanban board, a
|
|
143
|
+
decision log, and bugs, shared with the human and with every other agent working
|
|
144
|
+
on the app. It is platform-side: nothing to install or provision. Start a session
|
|
145
|
+
by reading it, and keep it current while you build:
|
|
146
|
+
|
|
147
|
+
```cmd
|
|
148
|
+
npx @odla-ai/cli pm task list --app <appId> --column doing
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Record a **decision** the moment you make one (with what it rules out), file a
|
|
152
|
+
**bug** the moment you notice one, and move a **task** when the work moves. A
|
|
153
|
+
decision you don't record is one the next agent re-litigates. Full command set,
|
|
154
|
+
conventions, and the read-first session opener: `references/pm.md`.
|
|
155
|
+
|
|
156
|
+
## Operational runbooks live in the database, not in this bundle
|
|
157
|
+
|
|
158
|
+
This bundle covers **setup**, pinned to the CLI version you installed. Operational
|
|
159
|
+
procedures — releasing, backups, database and code-runtime operations — are stored
|
|
160
|
+
in odla and change without a CLI release. Read one at the moment you follow it:
|
|
161
|
+
|
|
162
|
+
```cmd
|
|
163
|
+
npx @odla-ai/cli runbook list
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
```cmd
|
|
167
|
+
npx @odla-ai/cli runbook get release
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
`runbook get` prints raw markdown, so pipe it or read it directly. Do not follow a
|
|
171
|
+
multi-step platform procedure from memory, and never scrape odla.ai for one — the
|
|
172
|
+
CLI reads the same content authenticated and current.
|
|
173
|
+
|
|
174
|
+
Answering a question rather than following a procedure? `ask` returns a written,
|
|
175
|
+
cited answer; `search` returns the **sections** behind it, each with its source
|
|
176
|
+
and the command to pull the rest:
|
|
177
|
+
|
|
178
|
+
```cmd
|
|
179
|
+
npx @odla-ai/cli runbook ask "how do I roll back a bad publish?"
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
```cmd
|
|
183
|
+
npx @odla-ai/cli runbook search "roll back a bad publish"
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Cite what you quote — `release#rolling-back-a-bad-publish (v3)` — so the reader
|
|
187
|
+
can check it. An agent holding the PM skill has the same reach as tools:
|
|
188
|
+
`search_runbooks` (question in, cited sections out), `read_runbook` (whole
|
|
189
|
+
runbook, or one `section`), and `amend_runbook` for this project's own.
|
|
190
|
+
|
|
191
|
+
**A runbook is half the answer.** It carries the procedure — the order, the
|
|
192
|
+
gates, the commands. What an export takes, returns, and guarantees is the JSDoc
|
|
193
|
+
on that symbol: shipped in the installed package's `dist/*.d.ts` and rendered at
|
|
194
|
+
`https://odla.ai/docs/packages/<pkg>`. When a step calls an odla API, take the
|
|
195
|
+
step from the runbook and the arguments from the JSDoc. Never fill in a
|
|
196
|
+
signature, a default, or a return shape from memory — you do not have the
|
|
197
|
+
installed version in front of you, and the runbook is not claiming to describe it.
|
|
198
|
+
|
|
199
|
+
### After you change something, ask what you invalidated
|
|
200
|
+
|
|
201
|
+
```cmd
|
|
202
|
+
npx @odla-ai/cli runbook impact
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
It diffs your working tree against `origin/main` (`--base <ref>` for anything
|
|
206
|
+
else, uncommitted work included), works out which surfaces moved — the package,
|
|
207
|
+
the exports whose declaration or **JSDoc** changed, the console area — and names
|
|
208
|
+
the runbooks whose steps describe them, with the command to read each one.
|
|
209
|
+
|
|
210
|
+
Run it after touching an exported API, a doc comment, a package version, or a
|
|
211
|
+
Studio surface. Editing a JSDoc block is exactly the moment a procedure that
|
|
212
|
+
quotes that API can go stale, and nothing else will catch it: a runbook lives in
|
|
213
|
+
the database, so no build, test, or CI gate in the repository can see it drift
|
|
214
|
+
from your code. Reread what it names and fix any step your change made wrong,
|
|
215
|
+
in the same piece of work.
|
|
216
|
+
|
|
217
|
+
The other direction — are the runbooks themselves still true?
|
|
218
|
+
|
|
219
|
+
```cmd
|
|
220
|
+
npx @odla-ai/cli runbook lint
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Every `odla-ai …` command the runbooks name is held against this CLI's real
|
|
224
|
+
command surface, and against the minimum versions each runbook declares. Because
|
|
225
|
+
a runbook is edited without a release, its text can name a command only a newer
|
|
226
|
+
package has; a runbook records that as `requires` (`@odla-ai/cli@0.18.0`), and
|
|
227
|
+
`runbook get` warns on stderr when yours is older. If you add a command and then
|
|
228
|
+
tell a runbook to use it, set `requires` in the same edit — otherwise the first
|
|
229
|
+
reader on an older CLI gets an "unknown action" error instead of an explanation.
|
|
230
|
+
|
|
231
|
+
Found a wrong step? Fix an app runbook directly. For a platform runbook,
|
|
232
|
+
`runbook edit` requests an admin-approved capability — a plain handshake token is
|
|
233
|
+
never admin, and `npx @odla-ai/cli whoami` tells you what you hold.
|
|
234
|
+
|
|
235
|
+
⏸ That request prints an approval block with a URL on its own line. **Relay that
|
|
236
|
+
URL to the human verbatim, immediately, before you wait on anything.** You cannot
|
|
237
|
+
approve it yourself — the grant is issued to you, not by you — and the command
|
|
238
|
+
blocks until a signed-in admin approves it. The browser launch is best-effort and
|
|
239
|
+
often shows no tab, so the printed URL is the only thing the human can rely on.
|
|
240
|
+
If approval is not available, comment on the runbook instead so an admin can fix
|
|
241
|
+
it later.
|
|
242
|
+
|
|
132
243
|
`npx @odla-ai/cli doctor` is an offline config check anytime;
|
|
133
244
|
`npx @odla-ai/cli smoke --env dev` verifies a live deployment.
|
|
134
245
|
Use `calendar status --json` for safe connection state (`bookable`, booking
|
|
@@ -163,6 +274,9 @@ code, paste a publishable key, run a command) — and wait for a nod.
|
|
|
163
274
|
exported TypeScript declarations/JSDoc (resolve entry points through its
|
|
164
275
|
`package.json` `exports`). Rendered references are also public at
|
|
165
276
|
`https://odla.ai/docs/packages/<pkg>`.
|
|
277
|
+
- `references/pm.md` — the project manager for agents: goals, board, decisions,
|
|
278
|
+
bugs. What to file where, the `pm` command set, and how to open and close a
|
|
279
|
+
session against it.
|
|
166
280
|
- `references/co-owners.md` — sharing one app's db and tooling across a team:
|
|
167
281
|
`app owners add/list/remove`, and how each co-owner self-provisions their own
|
|
168
282
|
credentials (dev and the shared prod database) without any secret handoff.
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# PM — the project's memory, for agents
|
|
2
|
+
|
|
3
|
+
odla ships a project manager built for the agents doing the work:
|
|
4
|
+
**conformance goals**, a kanban **board**, a **decision** log, and **bugs**. It is
|
|
5
|
+
not a status report for a human to read later — it is your working memory across
|
|
6
|
+
sessions, and the place another agent (or the human) picks up what you learned.
|
|
7
|
+
|
|
8
|
+
Use it. A decision you don't record is one the next agent re-litigates; a bug you
|
|
9
|
+
only mention in chat is a bug nobody fixes.
|
|
10
|
+
|
|
11
|
+
## What it is, mechanically
|
|
12
|
+
|
|
13
|
+
- PM data lives on the **platform**, in odla's own shared store — *not* in the
|
|
14
|
+
app's database. There is nothing to install, schema, or provision, and no
|
|
15
|
+
entry in `odla.config.mjs`.
|
|
16
|
+
- Every item is tagged with an **appId**, and access rides **app co-ownership**:
|
|
17
|
+
you see and write PM items for exactly the apps you co-own
|
|
18
|
+
(`references/co-owners.md`). Co-own three apps and one `pm bug list` spans all
|
|
19
|
+
three.
|
|
20
|
+
- Auth is the same developer device grant the rest of the CLI uses. The first
|
|
21
|
+
`pm` command in a fresh checkout may print an approval code — relay it to the
|
|
22
|
+
human verbatim, same as `provision`.
|
|
23
|
+
- The human's view of the same data is **https://odla.ai/studio/pm** (and each
|
|
24
|
+
app's **Project** tab in Studio): the board is drag-and-drop there, and every
|
|
25
|
+
section filters by project.
|
|
26
|
+
|
|
27
|
+
## The four things, and when each one is right
|
|
28
|
+
|
|
29
|
+
| You have | File it as | Because |
|
|
30
|
+
| --- | --- | --- |
|
|
31
|
+
| an outcome that must be true, plus the test that proves it | **goal** | it carries `--proof`; `pm goal done` means the proof passed, not "I think it works" |
|
|
32
|
+
| a specific unit of work | **task** | it has a board column, so the human can see what is moving |
|
|
33
|
+
| a choice that closes off alternatives | **decision** | the log is full-text searchable, so the *next* agent finds the why |
|
|
34
|
+
| something that is broken | **bug** | it has a severity and survives the session that noticed it |
|
|
35
|
+
|
|
36
|
+
Do not file a task per keystroke. One task per thing a human would recognise as a
|
|
37
|
+
piece of work; one decision per choice you would otherwise bury in a commit
|
|
38
|
+
message; one bug per defect.
|
|
39
|
+
|
|
40
|
+
## The commands
|
|
41
|
+
|
|
42
|
+
Entity is `goal | task | decision | bug`; every command takes `--json` for
|
|
43
|
+
machine-readable output.
|
|
44
|
+
|
|
45
|
+
```cmd
|
|
46
|
+
npx @odla-ai/cli pm bug add --app <appId> --title "Checkout 500s on retry" --severity high --desc "…"
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
```cmd
|
|
50
|
+
npx @odla-ai/cli pm bug list --app <appId> --status open
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
```cmd
|
|
54
|
+
npx @odla-ai/cli pm task set <id> --column doing
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
```cmd
|
|
58
|
+
npx @odla-ai/cli pm decision list --q "stripe"
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
- `add` needs `--app <appId>` and `--title`; it takes the entity's own fields
|
|
62
|
+
(`--proof`, `--target` for goals; `--column`, `--goal`, `--assignee`, `--due`
|
|
63
|
+
for tasks; `--body` for decisions; `--severity`, `--desc` for bugs).
|
|
64
|
+
- `list` filters with `--status`, `--severity`, `--column`, `--assignee`,
|
|
65
|
+
`--goal`, full-text `--q`, and pages with `--limit` / `--offset`. **With no
|
|
66
|
+
`--app` it spans every project you co-own** — that is the cross-project view,
|
|
67
|
+
and it is usually the one you want when you start a session.
|
|
68
|
+
- `get <id>` prints one item; `set <id> --<field> <value>` patches it
|
|
69
|
+
(`--no-<field>` clears an optional field); `done <id>` is the shortcut for the
|
|
70
|
+
terminal state (goal → met, task → done, decision → accepted, bug → fixed).
|
|
71
|
+
- `comment <id> --body "…"` and `comments <id>` are the item's discussion thread.
|
|
72
|
+
Status and column changes post there automatically, so the thread is the audit
|
|
73
|
+
trail — the human sees what you did without asking.
|
|
74
|
+
- `rm <id>` deletes. Prefer `done` or a status change; deletion loses the thread.
|
|
75
|
+
|
|
76
|
+
## Working with it
|
|
77
|
+
|
|
78
|
+
**At the start of a session**, read before you write:
|
|
79
|
+
|
|
80
|
+
```cmd
|
|
81
|
+
npx @odla-ai/cli pm task list --app <appId> --column doing
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
then `pm bug list --app <appId> --status open` and
|
|
85
|
+
`pm decision list --app <appId> --limit 10`. That is the state of the project in
|
|
86
|
+
three commands — including anything a *different* agent left behind.
|
|
87
|
+
|
|
88
|
+
**While you build:**
|
|
89
|
+
|
|
90
|
+
- Move the card when the work moves — `pm task set <id> --column doing` when you
|
|
91
|
+
start, `pm task done <id>` when it is really done (tests green, not "written").
|
|
92
|
+
- Record a decision the moment you make it, with what it rules out:
|
|
93
|
+
`pm decision add --app <appId> --title "Bun over tsx for the worker build"
|
|
94
|
+
--body "…"`. This is the single highest-value thing you can do here.
|
|
95
|
+
- File a bug the moment you notice it, even mid-task, even if it is not yours.
|
|
96
|
+
`--severity critical|high|medium|low`. Then keep going — the bug is captured,
|
|
97
|
+
so it does not have to derail what you are doing.
|
|
98
|
+
- A goal is how you say what "done" means before you start:
|
|
99
|
+
`pm goal add --app <appId> --title "Checkout survives a retry storm" --proof
|
|
100
|
+
"test/checkout-retry.test.ts"`. Mark it met only when that proof passes.
|
|
101
|
+
|
|
102
|
+
**Never** put a secret, a token, or a credential in a title, body, description,
|
|
103
|
+
or comment. PM items are shared with every co-owner of the app.
|
|
104
|
+
|
|
105
|
+
## Checkpoints
|
|
106
|
+
|
|
107
|
+
PM writes are not destructive and need no approval — file freely. Deleting an
|
|
108
|
+
item (`pm … rm`) and closing something you did not open are the two calls to
|
|
109
|
+
put to the human first.
|
|
@@ -12,6 +12,7 @@ default-deny `src/odla/rules.mjs`. Isomorphic (browser + Worker).
|
|
|
12
12
|
|
|
13
13
|
```ts
|
|
14
14
|
// browser client — token from your IdP (Clerk):
|
|
15
|
+
import { OdlaProvider, useQuery, useTransact } from "@odla-ai/db/preact";
|
|
15
16
|
const db = init({ appId, endpoint, getToken });
|
|
16
17
|
const { data } = useQuery({ notes: { $: { order: { createdAt: "asc" } } } });
|
|
17
18
|
transact(db.tx.notes[crypto.randomUUID()].update({ text, createdAt: Date.now() }));
|
|
@@ -20,7 +21,7 @@ transact(db.tx.notes[crypto.randomUUID()].update({ text, createdAt: Date.now() }
|
|
|
20
21
|
Worker/admin side: `init({ appId: tenantId, adminToken: env.ODLA_API_KEY, endpoint })`
|
|
21
22
|
— the admin key bypasses rules, so a worker-mediated backend needs none.
|
|
22
23
|
|
|
23
|
-
## @odla-ai/auth-clerk — sign-in (Clerk
|
|
24
|
+
## @odla-ai/auth-clerk — native Preact sign-in (Clerk)
|
|
24
25
|
|
|
25
26
|
```tsx
|
|
26
27
|
<ClerkGate publishableKey={pk} appearance={clerkAppearanceFromTokens()}>
|
|
@@ -158,10 +159,12 @@ injected isolated executor and never falls back to the host shell.
|
|
|
158
159
|
- **@odla-ai/chapter** — membership sites from one `defineChapter()` config:
|
|
159
160
|
generates the odla-db schema + deny-all rules + group seed + provisioning
|
|
160
161
|
integration, and ships the worker (join/apply, Stripe membership, Google
|
|
161
|
-
booking, member area, exactly-once lifecycle email, CRM projection
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
162
|
+
booking, member area, exactly-once lifecycle email, CRM projection, and
|
|
163
|
+
leader → follower record delivery) plus a UI kit. Composable:
|
|
164
|
+
`chapterWorker({ chapter, routes })` runs host routes before the built-ins and
|
|
165
|
+
shares its auth context; `<ChapterAdmin chapter={chapter}/>` derives the
|
|
166
|
+
familiar brand/section shell and uses host-independent `?tab=` routing;
|
|
167
|
+
`./ui/member` is Preact-only (no Clerk SDK). **If a migration target
|
|
165
168
|
is a membership site, start here instead of hand-authoring schema** — see
|
|
166
169
|
`odla-migrate/references/phase-2-chapter.md`.
|
|
167
170
|
- **@odla-ai/ui** — design system: CSS tokens, five themes, component styles,
|
|
@@ -42,7 +42,10 @@ installed skill at `../odla/SKILL.md` instead.
|
|
|
42
42
|
references/secrets-map.md BEFORE any command that touches a credential.
|
|
43
43
|
A fresh device request requires the existing odla account email via
|
|
44
44
|
`--email` or `ODLA_USER_EMAIL`; email is a non-secret identifier. Never ask
|
|
45
|
-
for an odla password, Clerk token, or browser session.
|
|
45
|
+
for an odla password, Clerk token, or browser session. That is the human's
|
|
46
|
+
odla ACCOUNT email — never infer it from `git config user.email`, `gh`, or a
|
|
47
|
+
commit author; a wrong address silently mints an unapprovable request. See
|
|
48
|
+
references/troubleshooting.md.
|
|
46
49
|
4. Never `git add -A` without reading `git status` first.
|
|
47
50
|
5. Never widen a db rule to silence a 403 — default-deny is the design.
|
|
48
51
|
Any rules change is a human checkpoint.
|
|
@@ -36,8 +36,14 @@ hand-author only the namespaces it does not.
|
|
|
36
36
|
hands each the same context (`ctx.verifyUser`, `ctx.makeDb`, `ctx.roleFor`,
|
|
37
37
|
`ctx.isAdmin`), so you never verify a JWT twice. Do NOT hand routes over to
|
|
38
38
|
chapter in the same change as the framework swap.
|
|
39
|
-
5. **
|
|
40
|
-
|
|
39
|
+
5. **Adopt the host-independent console shell.** Import
|
|
40
|
+
`@odla-ai/ui/themes/salt/app.css` once, then render
|
|
41
|
+
`<ChapterAdmin chapter={chapter}/>` at the existing `/admin/` mount. The
|
|
42
|
+
config supplies brand tokens and the standard sections. Navigation uses
|
|
43
|
+
`?tab=` by default, so do not add `/admin/*` SPA rewrites to an ordinary
|
|
44
|
+
static site. Legacy path links remain readable.
|
|
45
|
+
6. **Override rather than inherit wherever local behavior was a decision.**
|
|
46
|
+
7. `npx @odla-ai/cli doctor` → `provision --dry-run` (show the human) → provision.
|
|
41
47
|
|
|
42
48
|
The same parity-before-deletion pattern works for UI: render the packaged
|
|
43
49
|
component beside yours, assert byte-identical markup, then delete yours and keep
|
|
@@ -64,18 +70,23 @@ These bite silently; no smoke test catches them.
|
|
|
64
70
|
invitation**. Swapping in chapter's route while expecting server-side create
|
|
65
71
|
loses it silently unless you set `account: "create"` — the applicant finds out
|
|
66
72
|
when they cannot sign in.
|
|
67
|
-
- **CRM
|
|
68
|
-
|
|
69
|
-
|
|
73
|
+
- **CRM authority.** `applications` remains authoritative for member lifecycle;
|
|
74
|
+
`crm_record` mirrors identity, stage, billing, and Clerk linkage. Leader →
|
|
75
|
+
follower delivery intentionally copies allowlisted record fields only, not
|
|
76
|
+
another site's pipeline/account/billing authority.
|
|
70
77
|
- **Route names.** chapter serves `/api/config`, `/api/join-config`. Alias legacy
|
|
71
78
|
names in ~4 lines as host routes rather than rewriting pages.
|
|
79
|
+
- **Follower record types.** A follower rejects a pushed business/deal if its own
|
|
80
|
+
CRM does not declare that type and fields. Add the type to the follower config
|
|
81
|
+
and expose it through the standard console before enabling the target in the
|
|
82
|
+
leader.
|
|
72
83
|
|
|
73
84
|
## Install notes
|
|
74
85
|
|
|
75
86
|
- **A worker-only adoption does not need `@odla-ai/auth-clerk`.** The worker
|
|
76
87
|
verifies Clerk JWTs with `jose` via `ctx.verifyUser`. Install auth-clerk only
|
|
77
88
|
for `@odla-ai/chapter/ui/admin` (the Clerk-gated console) or the themed sign-in
|
|
78
|
-
components; `@odla-ai/chapter/ui/member` needs
|
|
89
|
+
components; `@odla-ai/chapter/ui/member` needs only Preact.
|
|
79
90
|
- **`--legacy-peer-deps` is a diagnostic, not a setting.** It suppresses exactly
|
|
80
91
|
the peer error that tells you a pair is unsupported. If an install errors, read
|
|
81
92
|
it. A site that left the flag on ran an unsupported ui/crm pair for a day with
|
|
@@ -108,10 +108,10 @@ this app's own Worker endpoints and may import pure helpers from
|
|
|
108
108
|
7. Frontend. Two supported shapes:
|
|
109
109
|
- **`@odla-ai/ui` SlotPicker** — renders the slots response directly
|
|
110
110
|
(`{ slots, timezone, onSelect }`). On a non-framework static site use a
|
|
111
|
-
Preact island: a small entry that
|
|
112
|
-
|
|
113
|
-
`preact
|
|
114
|
-
assets.
|
|
111
|
+
native Preact island: a small entry that imports `render` from `preact`,
|
|
112
|
+
mounts `<SlotPicker>` into an empty div, and bundles with
|
|
113
|
+
`jsxImportSource: "preact"` as an IIFE committed next to the site's other
|
|
114
|
+
assets. Do not install React or add compatibility aliases.
|
|
115
115
|
- **Plain fetch + buttons** — `fetch("/api/booking/slots")`, render times
|
|
116
116
|
with `formatBookingRange` from `@odla-ai/calendar/client`, POST the
|
|
117
117
|
chosen slot.
|
|
@@ -52,10 +52,10 @@ authoritative for commands and flags.
|
|
|
52
52
|
`{"email": "{{user.primary_email_address}}"}`
|
|
53
53
|
4. Gate at least one `/api/*` route on a verified user; return 401
|
|
54
54
|
otherwise.
|
|
55
|
-
5. Add Clerk sign-in to the site pages. For a
|
|
55
|
+
5. Add Clerk sign-in to the site pages. For a Preact site, use
|
|
56
56
|
`@odla-ai/auth-clerk`: wrap the app in `<ClerkGate publishableKey>`
|
|
57
57
|
(key from public-config) and drop in `<SignIn />`. It runs on vanilla
|
|
58
|
-
clerk-js (no
|
|
58
|
+
clerk-js (no React wrapper), loads clerk-js as a lazy chunk, and themes
|
|
59
59
|
to odla-ui via `clerkAppearanceFromTokens()`. Otherwise drive ClerkJS
|
|
60
60
|
directly with the publishable key from public-config, or use Clerk's
|
|
61
61
|
hosted pages. For a **vanilla/static site**, load Clerk's browser bundle
|
|
@@ -46,6 +46,29 @@ appearing), wait for them to approve, then re-run the same command; it
|
|
|
46
46
|
resumes the same code and collects the token. Do not loop unattended
|
|
47
47
|
retries; each handshake lives ~10 minutes.
|
|
48
48
|
|
|
49
|
+
## The approval URL says no request matches, or is never approvable
|
|
50
|
+
|
|
51
|
+
Symptom: the human opens the printed `/studio?code=XXXX-XXXX` link and Studio
|
|
52
|
+
says "No request for your account matches …", or they approve nothing because
|
|
53
|
+
no request card appears — while the CLI polls until the handshake expires.
|
|
54
|
+
|
|
55
|
+
Cause: `--email` / `ODLA_USER_EMAIL` was not the human's odla **account**
|
|
56
|
+
email. The registry matches the exact normalized string (`trim` + `lowercase`
|
|
57
|
+
only), so a `+alias`, a `users.noreply.github.com` address, or a second
|
|
58
|
+
personal address is a different identity. An address that resolves to no
|
|
59
|
+
account is **not** an error — to keep anyone from discovering which emails are
|
|
60
|
+
registered, the request is recorded as an inert decoy bound to no owner, which
|
|
61
|
+
no one can preview or approve. Every surface therefore looks normal: the CLI
|
|
62
|
+
prints a URL, polls, and times out.
|
|
63
|
+
|
|
64
|
+
Fix: confirm the address with the human and re-run. **Never derive it from
|
|
65
|
+
`git config user.email`, `gh`, or a commit author** — that is the usual source
|
|
66
|
+
of this, because a git identity is routinely a different address from the odla
|
|
67
|
+
account. If `.odla/handshake.local.json` exists, the address it records is
|
|
68
|
+
known-good; reuse that. Repeated failures with the same address mean it is not
|
|
69
|
+
registered — the human must add it to their account (or use the registered
|
|
70
|
+
one), and no amount of retrying will help.
|
|
71
|
+
|
|
49
72
|
## `smoke` fails: missing credentials
|
|
50
73
|
|
|
51
74
|
Cause: `.odla/credentials.local.json` absent, for a different app id,
|
|
@@ -95,3 +95,17 @@ suggest one (metric + threshold + window).
|
|
|
95
95
|
- **Say what you couldn't see.** Arbitrary custom attributes live in the trace
|
|
96
96
|
payload, not the group-by dimensions; if the cohort is defined by a custom
|
|
97
97
|
field, note that you inferred it from individual traces, not an aggregate.
|
|
98
|
+
|
|
99
|
+
## Land the finding
|
|
100
|
+
|
|
101
|
+
A triage that ends in chat is lost by the next session. File what you found as a
|
|
102
|
+
bug against the app, with the cohort in the description and the trace id in a
|
|
103
|
+
comment:
|
|
104
|
+
|
|
105
|
+
```cmd
|
|
106
|
+
npx @odla-ai/cli pm bug add --app <appId> --title "POST /pay 503s under retry" --severity high --desc "…"
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Severity follows the blast radius, not your confidence. The conventions and the
|
|
110
|
+
rest of the `pm` command set are in `.agents/skills/odla/references/pm.md`
|
|
111
|
+
(installed alongside this skill).
|