@productbrain/cli 0.1.0-beta.1 → 0.1.0-beta.15
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 +167 -0
- package/dist/__tests__/audit.test.d.ts +2 -0
- package/dist/__tests__/audit.test.d.ts.map +1 -0
- package/dist/__tests__/audit.test.js +394 -0
- package/dist/__tests__/audit.test.js.map +1 -0
- package/dist/__tests__/capture.test.d.ts +2 -0
- package/dist/__tests__/capture.test.d.ts.map +1 -0
- package/dist/__tests__/capture.test.js +86 -0
- package/dist/__tests__/capture.test.js.map +1 -0
- package/dist/__tests__/constellation.test.d.ts +2 -0
- package/dist/__tests__/constellation.test.d.ts.map +1 -0
- package/dist/__tests__/constellation.test.js +260 -0
- package/dist/__tests__/constellation.test.js.map +1 -0
- package/dist/__tests__/context-strategy.test.d.ts +2 -0
- package/dist/__tests__/context-strategy.test.d.ts.map +1 -0
- package/dist/__tests__/context-strategy.test.js +79 -0
- package/dist/__tests__/context-strategy.test.js.map +1 -0
- package/dist/__tests__/fields.test.d.ts +2 -0
- package/dist/__tests__/fields.test.d.ts.map +1 -0
- package/dist/__tests__/fields.test.js +238 -0
- package/dist/__tests__/fields.test.js.map +1 -0
- package/dist/__tests__/handshake.test.d.ts +2 -0
- package/dist/__tests__/handshake.test.d.ts.map +1 -0
- package/dist/__tests__/handshake.test.js +187 -0
- package/dist/__tests__/handshake.test.js.map +1 -0
- package/dist/__tests__/ingest.test.d.ts +2 -0
- package/dist/__tests__/ingest.test.d.ts.map +1 -0
- package/dist/__tests__/ingest.test.js +185 -0
- package/dist/__tests__/ingest.test.js.map +1 -0
- package/dist/__tests__/promote.test.d.ts +2 -0
- package/dist/__tests__/promote.test.d.ts.map +1 -0
- package/dist/__tests__/promote.test.js +139 -0
- package/dist/__tests__/promote.test.js.map +1 -0
- package/dist/__tests__/proposals.test.d.ts +2 -0
- package/dist/__tests__/proposals.test.d.ts.map +1 -0
- package/dist/__tests__/proposals.test.js +190 -0
- package/dist/__tests__/proposals.test.js.map +1 -0
- package/dist/__tests__/relate.test.d.ts +2 -0
- package/dist/__tests__/relate.test.d.ts.map +1 -0
- package/dist/__tests__/relate.test.js +105 -0
- package/dist/__tests__/relate.test.js.map +1 -0
- package/dist/__tests__/repo-detect.test.d.ts +2 -0
- package/dist/__tests__/repo-detect.test.d.ts.map +1 -0
- package/dist/__tests__/repo-detect.test.js +119 -0
- package/dist/__tests__/repo-detect.test.js.map +1 -0
- package/dist/__tests__/runner.test.d.ts +2 -0
- package/dist/__tests__/runner.test.d.ts.map +1 -0
- package/dist/__tests__/runner.test.js +215 -0
- package/dist/__tests__/runner.test.js.map +1 -0
- package/dist/__tests__/session-touch.test.d.ts +2 -0
- package/dist/__tests__/session-touch.test.d.ts.map +1 -0
- package/dist/__tests__/session-touch.test.js +134 -0
- package/dist/__tests__/session-touch.test.js.map +1 -0
- package/dist/__tests__/session.test.d.ts +2 -0
- package/dist/__tests__/session.test.d.ts.map +1 -0
- package/dist/__tests__/session.test.js +52 -0
- package/dist/__tests__/session.test.js.map +1 -0
- package/dist/__tests__/strip.test.d.ts +2 -0
- package/dist/__tests__/strip.test.d.ts.map +1 -0
- package/dist/__tests__/strip.test.js +136 -0
- package/dist/__tests__/strip.test.js.map +1 -0
- package/dist/__tests__/update.test.d.ts +2 -0
- package/dist/__tests__/update.test.d.ts.map +1 -0
- package/dist/__tests__/update.test.js +237 -0
- package/dist/__tests__/update.test.js.map +1 -0
- package/dist/commands/accept.d.ts +18 -0
- package/dist/commands/accept.d.ts.map +1 -0
- package/dist/commands/accept.js +72 -0
- package/dist/commands/accept.js.map +1 -0
- package/dist/commands/audit.d.ts +25 -0
- package/dist/commands/audit.d.ts.map +1 -0
- package/dist/commands/audit.js +188 -0
- package/dist/commands/audit.js.map +1 -0
- package/dist/commands/brand-pack.d.ts +2 -0
- package/dist/commands/brand-pack.d.ts.map +1 -0
- package/dist/commands/brand-pack.js +25 -0
- package/dist/commands/brand-pack.js.map +1 -0
- package/dist/commands/brief.d.ts +28 -0
- package/dist/commands/brief.d.ts.map +1 -0
- package/dist/commands/brief.js +70 -0
- package/dist/commands/brief.js.map +1 -0
- package/dist/commands/capture.d.ts +25 -0
- package/dist/commands/capture.d.ts.map +1 -0
- package/dist/commands/capture.js +103 -0
- package/dist/commands/capture.js.map +1 -0
- package/dist/commands/chain-walk.d.ts +14 -0
- package/dist/commands/chain-walk.d.ts.map +1 -0
- package/dist/commands/chain-walk.js +33 -0
- package/dist/commands/chain-walk.js.map +1 -0
- package/dist/commands/changes.d.ts +11 -0
- package/dist/commands/changes.d.ts.map +1 -0
- package/dist/commands/changes.js +41 -0
- package/dist/commands/changes.js.map +1 -0
- package/dist/commands/constellation.d.ts +11 -0
- package/dist/commands/constellation.d.ts.map +1 -0
- package/dist/commands/constellation.js +28 -0
- package/dist/commands/constellation.js.map +1 -0
- package/dist/commands/context.d.ts +2 -1
- package/dist/commands/context.d.ts.map +1 -1
- package/dist/commands/context.js +19 -9
- package/dist/commands/context.js.map +1 -1
- package/dist/commands/cross-cut.d.ts +11 -0
- package/dist/commands/cross-cut.d.ts.map +1 -0
- package/dist/commands/cross-cut.js +23 -0
- package/dist/commands/cross-cut.js.map +1 -0
- package/dist/commands/fields.d.ts +9 -0
- package/dist/commands/fields.d.ts.map +1 -0
- package/dist/commands/fields.js +26 -0
- package/dist/commands/fields.js.map +1 -0
- package/dist/commands/get.d.ts +8 -1
- package/dist/commands/get.d.ts.map +1 -1
- package/dist/commands/get.js +55 -6
- package/dist/commands/get.js.map +1 -1
- package/dist/commands/handshake.d.ts +18 -0
- package/dist/commands/handshake.d.ts.map +1 -0
- package/dist/commands/handshake.js +378 -0
- package/dist/commands/handshake.js.map +1 -0
- package/dist/commands/ingest.d.ts +14 -0
- package/dist/commands/ingest.d.ts.map +1 -0
- package/dist/commands/ingest.js +181 -0
- package/dist/commands/ingest.js.map +1 -0
- package/dist/commands/login.d.ts +5 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +53 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/orient.d.ts +2 -0
- package/dist/commands/orient.d.ts.map +1 -1
- package/dist/commands/orient.js +17 -8
- package/dist/commands/orient.js.map +1 -1
- package/dist/commands/promote.d.ts +12 -0
- package/dist/commands/promote.d.ts.map +1 -0
- package/dist/commands/promote.js +48 -0
- package/dist/commands/promote.js.map +1 -0
- package/dist/commands/proposals.d.ts +9 -0
- package/dist/commands/proposals.d.ts.map +1 -0
- package/dist/commands/proposals.js +24 -0
- package/dist/commands/proposals.js.map +1 -0
- package/dist/commands/reject.d.ts +14 -0
- package/dist/commands/reject.d.ts.map +1 -0
- package/dist/commands/reject.js +37 -0
- package/dist/commands/reject.js.map +1 -0
- package/dist/commands/relate.d.ts +16 -0
- package/dist/commands/relate.d.ts.map +1 -0
- package/dist/commands/relate.js +80 -0
- package/dist/commands/relate.js.map +1 -0
- package/dist/commands/search.d.ts +1 -0
- package/dist/commands/search.d.ts.map +1 -1
- package/dist/commands/search.js +9 -3
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/session.d.ts +20 -0
- package/dist/commands/session.d.ts.map +1 -0
- package/dist/commands/session.js +134 -0
- package/dist/commands/session.js.map +1 -0
- package/dist/commands/update.d.ts +16 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +139 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/verify.d.ts +13 -0
- package/dist/commands/verify.d.ts.map +1 -0
- package/dist/commands/verify.js +43 -0
- package/dist/commands/verify.js.map +1 -0
- package/dist/formatters/audit.d.ts +46 -0
- package/dist/formatters/audit.d.ts.map +1 -0
- package/dist/formatters/audit.js +81 -0
- package/dist/formatters/audit.js.map +1 -0
- package/dist/formatters/brief.d.ts +112 -0
- package/dist/formatters/brief.d.ts.map +1 -0
- package/dist/formatters/brief.js +179 -0
- package/dist/formatters/brief.js.map +1 -0
- package/dist/formatters/capture.d.ts +30 -0
- package/dist/formatters/capture.d.ts.map +1 -0
- package/dist/formatters/capture.js +58 -0
- package/dist/formatters/capture.js.map +1 -0
- package/dist/formatters/chain-walk.d.ts +33 -0
- package/dist/formatters/chain-walk.d.ts.map +1 -0
- package/dist/formatters/chain-walk.js +54 -0
- package/dist/formatters/chain-walk.js.map +1 -0
- package/dist/formatters/changes.d.ts +25 -0
- package/dist/formatters/changes.d.ts.map +1 -0
- package/dist/formatters/changes.js +60 -0
- package/dist/formatters/changes.js.map +1 -0
- package/dist/formatters/constellation.d.ts +34 -0
- package/dist/formatters/constellation.d.ts.map +1 -0
- package/dist/formatters/constellation.js +38 -0
- package/dist/formatters/constellation.js.map +1 -0
- package/dist/formatters/cross-cut.d.ts +21 -0
- package/dist/formatters/cross-cut.d.ts.map +1 -0
- package/dist/formatters/cross-cut.js +32 -0
- package/dist/formatters/cross-cut.js.map +1 -0
- package/dist/formatters/entry.d.ts +11 -0
- package/dist/formatters/entry.d.ts.map +1 -1
- package/dist/formatters/entry.js +14 -1
- package/dist/formatters/entry.js.map +1 -1
- package/dist/formatters/fields.d.ts +32 -0
- package/dist/formatters/fields.d.ts.map +1 -0
- package/dist/formatters/fields.js +49 -0
- package/dist/formatters/fields.js.map +1 -0
- package/dist/formatters/handshake.d.ts +17 -0
- package/dist/formatters/handshake.d.ts.map +1 -0
- package/dist/formatters/handshake.js +51 -0
- package/dist/formatters/handshake.js.map +1 -0
- package/dist/formatters/orient.d.ts +1 -0
- package/dist/formatters/orient.d.ts.map +1 -1
- package/dist/formatters/orient.js +4 -2
- package/dist/formatters/orient.js.map +1 -1
- package/dist/formatters/promote.d.ts +29 -0
- package/dist/formatters/promote.d.ts.map +1 -0
- package/dist/formatters/promote.js +38 -0
- package/dist/formatters/promote.js.map +1 -0
- package/dist/formatters/proposals.d.ts +45 -0
- package/dist/formatters/proposals.d.ts.map +1 -0
- package/dist/formatters/proposals.js +62 -0
- package/dist/formatters/proposals.js.map +1 -0
- package/dist/formatters/relate.d.ts +12 -0
- package/dist/formatters/relate.d.ts.map +1 -0
- package/dist/formatters/relate.js +13 -0
- package/dist/formatters/relate.js.map +1 -0
- package/dist/formatters/session.d.ts +11 -0
- package/dist/formatters/session.d.ts.map +1 -0
- package/dist/formatters/session.js +51 -0
- package/dist/formatters/session.js.map +1 -0
- package/dist/formatters/update.d.ts +17 -0
- package/dist/formatters/update.d.ts.map +1 -0
- package/dist/formatters/update.js +43 -0
- package/dist/formatters/update.js.map +1 -0
- package/dist/formatters/verify.d.ts +11 -0
- package/dist/formatters/verify.d.ts.map +1 -0
- package/dist/formatters/verify.js +11 -0
- package/dist/formatters/verify.js.map +1 -0
- package/dist/generators/adapters.d.ts +10 -0
- package/dist/generators/adapters.d.ts.map +1 -0
- package/dist/generators/adapters.js +102 -0
- package/dist/generators/adapters.js.map +1 -0
- package/dist/generators/briefing-md.d.ts +8 -0
- package/dist/generators/briefing-md.d.ts.map +1 -0
- package/dist/generators/briefing-md.js +51 -0
- package/dist/generators/briefing-md.js.map +1 -0
- package/dist/generators/context-md.d.ts +8 -0
- package/dist/generators/context-md.d.ts.map +1 -0
- package/dist/generators/context-md.js +123 -0
- package/dist/generators/context-md.js.map +1 -0
- package/dist/generators/portable-knowledge.d.ts +72 -0
- package/dist/generators/portable-knowledge.d.ts.map +1 -0
- package/dist/generators/portable-knowledge.js +246 -0
- package/dist/generators/portable-knowledge.js.map +1 -0
- package/dist/generators/portable-knowledge.test.d.ts +2 -0
- package/dist/generators/portable-knowledge.test.d.ts.map +1 -0
- package/dist/generators/portable-knowledge.test.js +399 -0
- package/dist/generators/portable-knowledge.test.js.map +1 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +466 -6
- package/dist/index.js.map +1 -1
- package/dist/lib/client.d.ts +34 -0
- package/dist/lib/client.d.ts.map +1 -1
- package/dist/lib/client.js +114 -9
- package/dist/lib/client.js.map +1 -1
- package/dist/lib/config.d.ts +19 -2
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +95 -14
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/repo-detect.d.ts +14 -0
- package/dist/lib/repo-detect.d.ts.map +1 -0
- package/dist/lib/repo-detect.js +58 -0
- package/dist/lib/repo-detect.js.map +1 -0
- package/dist/lib/runner.d.ts +31 -0
- package/dist/lib/runner.d.ts.map +1 -0
- package/dist/lib/runner.js +65 -0
- package/dist/lib/runner.js.map +1 -0
- package/dist/lib/session.d.ts +17 -0
- package/dist/lib/session.d.ts.map +1 -0
- package/dist/lib/session.js +43 -0
- package/dist/lib/session.js.map +1 -0
- package/dist/lib/strip.d.ts +11 -0
- package/dist/lib/strip.d.ts.map +1 -0
- package/dist/lib/strip.js +26 -0
- package/dist/lib/strip.js.map +1 -0
- package/package.json +8 -4
package/README.md
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# Product Brain CLI (`pb`)
|
|
2
|
+
|
|
3
|
+
CLI for Chain knowledge: read, search, gather context, and **write back**. Uses your Product Brain API key (same as MCP). Write commands require a readwrite key.
|
|
4
|
+
|
|
5
|
+
**Requirements:** Node 18+, API key from Product Brain → Settings → API Keys (`pb_sk_*`).
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
### From npm (beta)
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install -g @productbrain/cli@beta
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Updates require a new publish to npm (and, if you use 2FA, a one-time password). Use this when you want a stable beta from the registry.
|
|
18
|
+
|
|
19
|
+
### From main (no publish needed)
|
|
20
|
+
|
|
21
|
+
If you have the repo and want **latest from `main`** without publishing to npm:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
git clone https://github.com/synergyai-os/Product-OS.git
|
|
25
|
+
cd Product-OS
|
|
26
|
+
npm ci
|
|
27
|
+
cd packages/cli && npm run build && npm install -g .
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
After that, `pb` runs from your global path. Pull and re-run the last two commands to update:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
cd Product-OS && git pull && cd packages/cli && npm run build && npm install -g .
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
See [Deployment strategy — CLI vs MCP](../../docs/deployment-strategy.md#cli-vs-mcp-distribution) for why this avoids `cli:publish` / OTP.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## First run
|
|
41
|
+
|
|
42
|
+
- **No key yet:** Run any command (e.g. `pb orient -b`). You’ll get a short guided flow: “Do you have an API key? (y/n)” → paste key → saved to `~/.config/productbrain/.env`. Your command then runs.
|
|
43
|
+
- **Or:** Run `pb login` to paste and save your key once. Get a key: Product Brain app → Settings → API Keys.
|
|
44
|
+
|
|
45
|
+
Config is read from (in order): env vars → `~/.config/productbrain/.env` → `.env.mcp` in the current directory.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Commands
|
|
50
|
+
|
|
51
|
+
### Read (no session required)
|
|
52
|
+
|
|
53
|
+
| Command | Description |
|
|
54
|
+
|--------|-------------|
|
|
55
|
+
| `pb orient` | Workspace stage, bets, governance, tensions. Use `-b` for a brief view. |
|
|
56
|
+
| `pb search <query>` | Full-text search across the Chain. |
|
|
57
|
+
| `pb get <entry-id>` | Full entry (data, relations, last 10 history events). |
|
|
58
|
+
| `pb context <entry-id>` | Constellation context (pipe-friendly markdown when not a TTY). |
|
|
59
|
+
| `pb handshake` | Generate context files for AI developer tools. See below. |
|
|
60
|
+
| `pb login` | Save your API key to `~/.config/productbrain/.env`. |
|
|
61
|
+
|
|
62
|
+
**Internal (Product-OS repo only):** `pb brand-pack` forwards to `scripts/brand-pack.mjs` — structured community marketing JSON via **OpenRouter** (`OPENROUTER_API_KEY`, not the Product Brain API key). Use `npm run brand-pack -- --help` from repo root for script options. Not published behavior for global npm installs unless built from this monorepo.
|
|
63
|
+
|
|
64
|
+
### Write (session required — DEC-9)
|
|
65
|
+
|
|
66
|
+
| Command | Description |
|
|
67
|
+
|--------|-------------|
|
|
68
|
+
| `pb session start` | Open a tracked write session. Refreshes context files. |
|
|
69
|
+
| `pb capture "<text>"` | Capture a decision, tension, insight, or any knowledge to the Chain. Auto-classifies. |
|
|
70
|
+
| `pb session close` | Close the session. Shows captured entries, runs wrapup, refreshes context. |
|
|
71
|
+
|
|
72
|
+
`pb --help` for options.
|
|
73
|
+
|
|
74
|
+
### Delivery + Chain (when you ship code in Product-OS)
|
|
75
|
+
|
|
76
|
+
Progressive delivery and deploy ordering are documented in the monorepo — not inside the `pb` binary:
|
|
77
|
+
|
|
78
|
+
| SSOT | Purpose |
|
|
79
|
+
|------|---------|
|
|
80
|
+
| [`docs/system/design/progressive-delivery-thesis.md`](../../docs/system/design/progressive-delivery-thesis.md) | Ladder (dark launch → GA), rollback (**STA-10**), flags, edge/Cloudflare notes |
|
|
81
|
+
| **MAP-13** on the Chain | Map entry pointing at the thesis — `pb get MAP-13` / `pb context MAP-13` |
|
|
82
|
+
| [`docs/deployment-strategy.md`](../../docs/deployment-strategy.md) | CI target, Convex vs Railway, CLI vs MCP distribution |
|
|
83
|
+
|
|
84
|
+
**BR-157:** If your push includes changes under `convex/`, run **`npx convex deploy`** (correct deployment) **before** `git push origin main` so Railway never serves a frontend that calls missing Convex functions.
|
|
85
|
+
|
|
86
|
+
**Typical ship loop with `pb`:**
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
pb session start
|
|
90
|
+
# … commit, merge, push per .productbrain/skills/commit-to-main …
|
|
91
|
+
pb capture "DEC: Shipped <short>. Rollback: <flag OFF | Railway revert | …>. Convex deploy before push: <yes | N/A>."
|
|
92
|
+
pb session close
|
|
93
|
+
# If you changed .productbrain rules or skills:
|
|
94
|
+
cd ../.. && pb handshake # from repo root
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## `pb handshake` — AI Developer Onboarding
|
|
100
|
+
|
|
101
|
+
One command generates context files for every major AI coding tool:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
pb handshake
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
**What it generates:**
|
|
108
|
+
|
|
109
|
+
| File | Purpose |
|
|
110
|
+
|------|---------|
|
|
111
|
+
| `.productbrain/context.md` | Workspace briefing — stage, bets, governance, architecture, tensions |
|
|
112
|
+
| `.productbrain/briefing.md` | Chain entries matched to this specific repo |
|
|
113
|
+
| `CLAUDE.md` | Adapter for Claude Code |
|
|
114
|
+
| `.cursor/rules/chain.mdc` | Adapter for Cursor |
|
|
115
|
+
| `.github/copilot-instructions.md` | Adapter for GitHub Copilot |
|
|
116
|
+
|
|
117
|
+
**Options:**
|
|
118
|
+
|
|
119
|
+
- `--force` — Overwrite adapter files even if they have custom content
|
|
120
|
+
- `--dry-run` — Preview what would be generated without writing files
|
|
121
|
+
|
|
122
|
+
**Safety:** Adapter files are marked with `auto-generated by pb handshake`. If you customize one and remove the marker, future runs skip it (unless `--force`). The `.productbrain/` directory contains workspace-specific context and should be in `.gitignore`.
|
|
123
|
+
|
|
124
|
+
**Governance:** Context export surface per DEC-161 and GLO-63. Architecture: ARCH-63 (surfaces are peers consuming the kernel).
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## `pb session` + `pb capture` — Close the Loop
|
|
129
|
+
|
|
130
|
+
The Chain compounds from every AI coding session. Instead of knowledge dying in chat transcripts (TEN-27), capture it as you work.
|
|
131
|
+
|
|
132
|
+
### Flow
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
# Start of session
|
|
136
|
+
pb session start # opens session, refreshes context
|
|
137
|
+
|
|
138
|
+
# During work — capture what you learn
|
|
139
|
+
pb capture "TEN: topology query returns stale containers when initiatives are archived"
|
|
140
|
+
pb capture "DEC: excluded archived initiatives at the query level, not the UI filter"
|
|
141
|
+
pb capture "INS: learned that the containerIds array references soft-deleted entries"
|
|
142
|
+
|
|
143
|
+
# End of session
|
|
144
|
+
pb session close # shows summary, runs wrapup, refreshes context
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### How capture works
|
|
148
|
+
|
|
149
|
+
1. Text is sent to the Chain's classification pipeline — auto-assigns collection
|
|
150
|
+
2. Entry is created as a **draft** (nothing auto-commits)
|
|
151
|
+
3. Receipt shows: entry ID, collection, confidence, reasoning, alternatives
|
|
152
|
+
4. You review and commit drafts in Product Brain Studio
|
|
153
|
+
|
|
154
|
+
### Options
|
|
155
|
+
|
|
156
|
+
- `pb capture --collection tensions "text"` — skip auto-classification, use explicit collection
|
|
157
|
+
- `pb capture --name "Short title" --description "Full explanation"` — separate name and description
|
|
158
|
+
- `pb session close --force` — clear local session state even if server close fails
|
|
159
|
+
|
|
160
|
+
### Governance
|
|
161
|
+
|
|
162
|
+
- Write access requires a tracked session (DEC-9, BR-8)
|
|
163
|
+
- Session attribution via API key; `clientKind: 'cli'` discriminator per DEC-184 (pending schema extension)
|
|
164
|
+
- All captures are drafts — human reviews and commits (TEN-374)
|
|
165
|
+
- Solves TEN-264 (CLI write access session attribution) with explicit session token in `.productbrain/session.json`
|
|
166
|
+
- Addresses TEN-27 (strategic conversations generate decisions that never reach the Chain)
|
|
167
|
+
- Implements INS-80 (proactive capture during coding)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/audit.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pb audit — unit tests.
|
|
3
|
+
* BET-182 Slice 2: CLI command + auto-fix.
|
|
4
|
+
*
|
|
5
|
+
* Verifies:
|
|
6
|
+
* 1. JSON mode: correct structure on pipe (mock mcpCall with fixture)
|
|
7
|
+
* 2. TTY mode: PASS gates collapsed, FAIL gates expanded
|
|
8
|
+
* 3. Exit codes: 0/1/2/3 for each verdict
|
|
9
|
+
* 4. --gate flag: only specified gate runs
|
|
10
|
+
* 5. --phase flag: passed through to MCP call
|
|
11
|
+
* 6. --fix: calls update with fix values, reruns audit, stops after 1 rerun
|
|
12
|
+
* 7. Batch mode: multiple entryIds processed sequentially
|
|
13
|
+
* 8. Edge case: entry not found returns error
|
|
14
|
+
*/
|
|
15
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
16
|
+
import { runAudit } from '../commands/audit.js';
|
|
17
|
+
import { setOutputMode } from '../lib/runner.js';
|
|
18
|
+
const mcpCallMock = vi.fn();
|
|
19
|
+
const mcpCallWithSessionMock = vi.fn();
|
|
20
|
+
vi.mock('../lib/client.js', () => ({
|
|
21
|
+
mcpCall: (...args) => mcpCallMock(...args),
|
|
22
|
+
mcpCallWithSession: (...args) => mcpCallWithSessionMock(...args),
|
|
23
|
+
}));
|
|
24
|
+
vi.mock('../lib/config.js', () => ({
|
|
25
|
+
getConfigOrGuide: vi.fn((_fn) => Promise.resolve({ apiKey: 'pb_sk_test', siteUrl: 'https://test.convex.site' })),
|
|
26
|
+
}));
|
|
27
|
+
// Session mock — controlled per test
|
|
28
|
+
let mockSession = { sessionId: 'sess-test' };
|
|
29
|
+
vi.mock('../lib/session.js', () => ({
|
|
30
|
+
readSession: () => mockSession,
|
|
31
|
+
}));
|
|
32
|
+
// ─── Fixtures ───────────────────────────────────────────────────────────────
|
|
33
|
+
const PASS_FIXTURE = {
|
|
34
|
+
entryId: 'BET-182',
|
|
35
|
+
entryName: 'CLI Audit Gate',
|
|
36
|
+
phase: 'shaping',
|
|
37
|
+
verdict: 'pass',
|
|
38
|
+
gates: [
|
|
39
|
+
{ gate: 'intentional-relations', status: 'pass', blocking: true, detail: '3 intentional relations found' },
|
|
40
|
+
{ gate: 'strategic-anchor', status: 'pass', blocking: true, detail: 'Linked to WS-5' },
|
|
41
|
+
{ gate: 'field-completeness', status: 'pass', blocking: true, detail: 'All 4 required fields populated' },
|
|
42
|
+
],
|
|
43
|
+
summary: { total: 3, passed: 3, failed: 0, warned: 0 },
|
|
44
|
+
elapsed_ms: 42,
|
|
45
|
+
};
|
|
46
|
+
const FAIL_FIXTURE = {
|
|
47
|
+
entryId: 'BET-200',
|
|
48
|
+
entryName: 'Broken Bet',
|
|
49
|
+
phase: 'shaping',
|
|
50
|
+
verdict: 'fail',
|
|
51
|
+
gates: [
|
|
52
|
+
{ gate: 'intentional-relations', status: 'fail', blocking: true, detail: '0 intentional relations', fix: "Set field 'problem' to 'needs definition'", fixType: 'exact' },
|
|
53
|
+
{ gate: 'strategic-anchor', status: 'pass', blocking: true, detail: 'Linked to WS-5' },
|
|
54
|
+
{ gate: 'field-completeness', status: 'fail', blocking: true, detail: 'Missing: appetite, doneWhen', fix: "Set field 'appetite' to '6 weeks'", fixType: 'exact', hint: 'STD-113 requires these fields' },
|
|
55
|
+
],
|
|
56
|
+
summary: { total: 3, passed: 1, failed: 2, warned: 0 },
|
|
57
|
+
elapsed_ms: 55,
|
|
58
|
+
};
|
|
59
|
+
const WARN_FIXTURE = {
|
|
60
|
+
entryId: 'BET-201',
|
|
61
|
+
entryName: 'Warn Bet',
|
|
62
|
+
phase: 'handoff',
|
|
63
|
+
verdict: 'warn',
|
|
64
|
+
gates: [
|
|
65
|
+
{ gate: 'auto-link-noise', status: 'warn', blocking: false, detail: '2 auto-link relations found', hint: 'Consider removing auto-link noise' },
|
|
66
|
+
{ gate: 'strategic-anchor', status: 'pass', blocking: true, detail: 'Linked to WS-5' },
|
|
67
|
+
],
|
|
68
|
+
summary: { total: 2, passed: 1, failed: 0, warned: 1 },
|
|
69
|
+
elapsed_ms: 33,
|
|
70
|
+
};
|
|
71
|
+
// ─── Helpers ────────────────────────────────────────────────────────────────
|
|
72
|
+
let stdoutOutput;
|
|
73
|
+
let stderrOutput;
|
|
74
|
+
let stdoutWriteSpy;
|
|
75
|
+
let stderrWriteSpy;
|
|
76
|
+
let exitSpy;
|
|
77
|
+
function withTty(isTty, fn) {
|
|
78
|
+
return async () => {
|
|
79
|
+
const original = process.stdout.isTTY;
|
|
80
|
+
Object.defineProperty(process.stdout, 'isTTY', { value: isTty, configurable: true, writable: true });
|
|
81
|
+
try {
|
|
82
|
+
await fn();
|
|
83
|
+
}
|
|
84
|
+
finally {
|
|
85
|
+
Object.defineProperty(process.stdout, 'isTTY', { value: original, configurable: true, writable: true });
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Catch process.exit without actually exiting.
|
|
91
|
+
* Returns the exit code that was called with.
|
|
92
|
+
*/
|
|
93
|
+
function catchExit() {
|
|
94
|
+
const state = { code: undefined };
|
|
95
|
+
exitSpy = vi.spyOn(process, 'exit').mockImplementation(((code) => {
|
|
96
|
+
state.code = code;
|
|
97
|
+
throw new Error(`process.exit(${code})`);
|
|
98
|
+
}));
|
|
99
|
+
return state;
|
|
100
|
+
}
|
|
101
|
+
beforeEach(() => {
|
|
102
|
+
stdoutOutput = '';
|
|
103
|
+
stderrOutput = '';
|
|
104
|
+
stdoutWriteSpy = vi.spyOn(process.stdout, 'write').mockImplementation((chunk) => {
|
|
105
|
+
stdoutOutput += String(chunk);
|
|
106
|
+
return true;
|
|
107
|
+
});
|
|
108
|
+
stderrWriteSpy = vi.spyOn(process.stderr, 'write').mockImplementation((chunk) => {
|
|
109
|
+
stderrOutput += String(chunk);
|
|
110
|
+
return true;
|
|
111
|
+
});
|
|
112
|
+
setOutputMode('auto');
|
|
113
|
+
mockSession = { sessionId: 'sess-test' };
|
|
114
|
+
vi.clearAllMocks();
|
|
115
|
+
});
|
|
116
|
+
afterEach(() => {
|
|
117
|
+
stdoutWriteSpy.mockRestore();
|
|
118
|
+
stderrWriteSpy.mockRestore();
|
|
119
|
+
exitSpy?.mockRestore();
|
|
120
|
+
setOutputMode('auto');
|
|
121
|
+
});
|
|
122
|
+
// ─── Tests ──────────────────────────────────────────────────────────────────
|
|
123
|
+
describe('runAudit — JSON mode (non-TTY)', () => {
|
|
124
|
+
it('outputs correct JSON structure on pipe', withTty(false, async () => {
|
|
125
|
+
mcpCallMock.mockResolvedValue(PASS_FIXTURE);
|
|
126
|
+
const exit = catchExit();
|
|
127
|
+
await expect(runAudit({ entryIds: ['BET-182'] })).rejects.toThrow('process.exit');
|
|
128
|
+
const parsed = JSON.parse(stdoutOutput);
|
|
129
|
+
expect(parsed.entryId).toBe('BET-182');
|
|
130
|
+
expect(parsed.entryName).toBe('CLI Audit Gate');
|
|
131
|
+
expect(parsed.verdict).toBe('pass');
|
|
132
|
+
expect(parsed.gates).toHaveLength(3);
|
|
133
|
+
expect(parsed.summary).toEqual({ total: 3, passed: 3, failed: 0, warned: 0 });
|
|
134
|
+
expect(parsed.elapsed_ms).toBe(42);
|
|
135
|
+
expect(exit.code).toBe(0);
|
|
136
|
+
}));
|
|
137
|
+
it('calls chain.auditBet with correct entryId', withTty(false, async () => {
|
|
138
|
+
mcpCallMock.mockResolvedValue(PASS_FIXTURE);
|
|
139
|
+
catchExit();
|
|
140
|
+
await expect(runAudit({ entryIds: ['BET-182'] })).rejects.toThrow('process.exit');
|
|
141
|
+
expect(mcpCallMock).toHaveBeenCalledWith('chain.auditBet', { entryId: 'BET-182' });
|
|
142
|
+
}));
|
|
143
|
+
it('strips Convex internals from JSON output', withTty(false, async () => {
|
|
144
|
+
const fixtureWithInternals = {
|
|
145
|
+
...PASS_FIXTURE,
|
|
146
|
+
_id: 'sys-internal-id',
|
|
147
|
+
_creationTime: 123456,
|
|
148
|
+
};
|
|
149
|
+
mcpCallMock.mockResolvedValue(fixtureWithInternals);
|
|
150
|
+
catchExit();
|
|
151
|
+
await expect(runAudit({ entryIds: ['BET-182'] })).rejects.toThrow('process.exit');
|
|
152
|
+
const parsed = JSON.parse(stdoutOutput);
|
|
153
|
+
expect(parsed).not.toHaveProperty('_id');
|
|
154
|
+
expect(parsed).not.toHaveProperty('_creationTime');
|
|
155
|
+
}));
|
|
156
|
+
});
|
|
157
|
+
describe('runAudit — TTY mode', () => {
|
|
158
|
+
it('collapses PASS gates (shows count), expands FAIL gates', withTty(true, async () => {
|
|
159
|
+
mcpCallMock.mockResolvedValue(FAIL_FIXTURE);
|
|
160
|
+
catchExit();
|
|
161
|
+
await expect(runAudit({ entryIds: ['BET-200'] })).rejects.toThrow('process.exit');
|
|
162
|
+
// FAIL gates should be expanded with detail
|
|
163
|
+
expect(stdoutOutput).toContain('intentional-relations');
|
|
164
|
+
expect(stdoutOutput).toContain('0 intentional relations');
|
|
165
|
+
expect(stdoutOutput).toContain('field-completeness');
|
|
166
|
+
expect(stdoutOutput).toContain('Missing: appetite, doneWhen');
|
|
167
|
+
// PASS gate should be in collapsed summary
|
|
168
|
+
expect(stdoutOutput).toContain('PASS: 1 gate(s)');
|
|
169
|
+
expect(stdoutOutput).toContain('strategic-anchor');
|
|
170
|
+
}));
|
|
171
|
+
it('shows WARN gates expanded with hints', withTty(true, async () => {
|
|
172
|
+
mcpCallMock.mockResolvedValue(WARN_FIXTURE);
|
|
173
|
+
catchExit();
|
|
174
|
+
await expect(runAudit({ entryIds: ['BET-201'] })).rejects.toThrow('process.exit');
|
|
175
|
+
expect(stdoutOutput).toContain('WARN:');
|
|
176
|
+
expect(stdoutOutput).toContain('auto-link-noise');
|
|
177
|
+
expect(stdoutOutput).toContain('2 auto-link relations found');
|
|
178
|
+
expect(stdoutOutput).toContain('Consider removing auto-link noise');
|
|
179
|
+
}));
|
|
180
|
+
it('--verbose expands all gates including PASS', withTty(true, async () => {
|
|
181
|
+
mcpCallMock.mockResolvedValue(PASS_FIXTURE);
|
|
182
|
+
catchExit();
|
|
183
|
+
await expect(runAudit({ entryIds: ['BET-182'], verbose: true })).rejects.toThrow('process.exit');
|
|
184
|
+
// PASS gates should show detail, not just count
|
|
185
|
+
expect(stdoutOutput).toContain('PASS:');
|
|
186
|
+
expect(stdoutOutput).toContain('intentional-relations: 3 intentional relations found');
|
|
187
|
+
expect(stdoutOutput).toContain('strategic-anchor: Linked to WS-5');
|
|
188
|
+
// Should NOT have the collapsed format
|
|
189
|
+
expect(stdoutOutput).not.toContain('gate(s)');
|
|
190
|
+
}));
|
|
191
|
+
});
|
|
192
|
+
describe('runAudit — exit codes', () => {
|
|
193
|
+
it('exit 0 for pass verdict', withTty(false, async () => {
|
|
194
|
+
mcpCallMock.mockResolvedValue(PASS_FIXTURE);
|
|
195
|
+
const exit = catchExit();
|
|
196
|
+
await expect(runAudit({ entryIds: ['BET-182'] })).rejects.toThrow('process.exit');
|
|
197
|
+
expect(exit.code).toBe(0);
|
|
198
|
+
}));
|
|
199
|
+
it('exit 1 for fail verdict', withTty(false, async () => {
|
|
200
|
+
mcpCallMock.mockResolvedValue(FAIL_FIXTURE);
|
|
201
|
+
const exit = catchExit();
|
|
202
|
+
await expect(runAudit({ entryIds: ['BET-200'] })).rejects.toThrow('process.exit');
|
|
203
|
+
expect(exit.code).toBe(1);
|
|
204
|
+
}));
|
|
205
|
+
it('exit 2 for warn verdict', withTty(false, async () => {
|
|
206
|
+
mcpCallMock.mockResolvedValue(WARN_FIXTURE);
|
|
207
|
+
const exit = catchExit();
|
|
208
|
+
await expect(runAudit({ entryIds: ['BET-201'] })).rejects.toThrow('process.exit');
|
|
209
|
+
expect(exit.code).toBe(2);
|
|
210
|
+
}));
|
|
211
|
+
it('exit 3 for error (entry not found)', withTty(false, async () => {
|
|
212
|
+
mcpCallMock.mockRejectedValue(new Error('Entry "BET-999" not found.'));
|
|
213
|
+
const exit = catchExit();
|
|
214
|
+
await expect(runAudit({ entryIds: ['BET-999'] })).rejects.toThrow('process.exit');
|
|
215
|
+
expect(exit.code).toBe(3);
|
|
216
|
+
}));
|
|
217
|
+
});
|
|
218
|
+
describe('runAudit — --gate flag', () => {
|
|
219
|
+
it('filters JSON output to only specified gate(s)', withTty(false, async () => {
|
|
220
|
+
mcpCallMock.mockResolvedValue(FAIL_FIXTURE);
|
|
221
|
+
catchExit();
|
|
222
|
+
await expect(runAudit({ entryIds: ['BET-200'], gate: ['field-completeness'] })).rejects.toThrow('process.exit');
|
|
223
|
+
const parsed = JSON.parse(stdoutOutput);
|
|
224
|
+
// Only the filtered gate should appear
|
|
225
|
+
expect(parsed.gates).toHaveLength(1);
|
|
226
|
+
expect(parsed.gates[0].gate).toBe('field-completeness');
|
|
227
|
+
}));
|
|
228
|
+
it('filters TTY output to only specified gate(s)', withTty(true, async () => {
|
|
229
|
+
mcpCallMock.mockResolvedValue(FAIL_FIXTURE);
|
|
230
|
+
catchExit();
|
|
231
|
+
await expect(runAudit({ entryIds: ['BET-200'], gate: ['field-completeness'] })).rejects.toThrow('process.exit');
|
|
232
|
+
// Should show the filtered gate
|
|
233
|
+
expect(stdoutOutput).toContain('field-completeness');
|
|
234
|
+
// Should NOT show other gates
|
|
235
|
+
expect(stdoutOutput).not.toContain('intentional-relations');
|
|
236
|
+
}));
|
|
237
|
+
it('supports multiple --gate values', withTty(false, async () => {
|
|
238
|
+
mcpCallMock.mockResolvedValue(FAIL_FIXTURE);
|
|
239
|
+
catchExit();
|
|
240
|
+
await expect(runAudit({ entryIds: ['BET-200'], gate: ['intentional-relations', 'field-completeness'] })).rejects.toThrow('process.exit');
|
|
241
|
+
const parsed = JSON.parse(stdoutOutput);
|
|
242
|
+
expect(parsed.gates).toHaveLength(2);
|
|
243
|
+
const gateNames = parsed.gates.map((g) => g.gate);
|
|
244
|
+
expect(gateNames).toContain('intentional-relations');
|
|
245
|
+
expect(gateNames).toContain('field-completeness');
|
|
246
|
+
}));
|
|
247
|
+
});
|
|
248
|
+
describe('runAudit — --phase flag', () => {
|
|
249
|
+
it('passes phase through to MCP call', withTty(false, async () => {
|
|
250
|
+
mcpCallMock.mockResolvedValue(PASS_FIXTURE);
|
|
251
|
+
catchExit();
|
|
252
|
+
await expect(runAudit({ entryIds: ['BET-182'], phase: 'handoff' })).rejects.toThrow('process.exit');
|
|
253
|
+
expect(mcpCallMock).toHaveBeenCalledWith('chain.auditBet', { entryId: 'BET-182', phase: 'handoff' });
|
|
254
|
+
}));
|
|
255
|
+
it('omits phase from MCP call when not specified', withTty(false, async () => {
|
|
256
|
+
mcpCallMock.mockResolvedValue(PASS_FIXTURE);
|
|
257
|
+
catchExit();
|
|
258
|
+
await expect(runAudit({ entryIds: ['BET-182'] })).rejects.toThrow('process.exit');
|
|
259
|
+
expect(mcpCallMock).toHaveBeenCalledWith('chain.auditBet', { entryId: 'BET-182' });
|
|
260
|
+
}));
|
|
261
|
+
});
|
|
262
|
+
describe('runAudit — --fix', () => {
|
|
263
|
+
it('calls updateEntry for exact fixes and reruns audit once', withTty(false, async () => {
|
|
264
|
+
// First call: failing audit
|
|
265
|
+
// Second call (after fix): passing audit
|
|
266
|
+
mcpCallMock
|
|
267
|
+
.mockResolvedValueOnce(FAIL_FIXTURE)
|
|
268
|
+
.mockResolvedValueOnce({ ...PASS_FIXTURE, entryId: 'BET-200', entryName: 'Broken Bet' });
|
|
269
|
+
mcpCallWithSessionMock.mockResolvedValue({ id: 'result-id', warnings: [] });
|
|
270
|
+
const exit = catchExit();
|
|
271
|
+
await expect(runAudit({ entryIds: ['BET-200'], fix: true })).rejects.toThrow('process.exit');
|
|
272
|
+
// Should have called updateEntry for each exact fix
|
|
273
|
+
expect(mcpCallWithSessionMock).toHaveBeenCalledWith('chain.updateEntry', {
|
|
274
|
+
entryId: 'BET-200',
|
|
275
|
+
data: { problem: 'needs definition' },
|
|
276
|
+
changeNote: 'Auto-fix via pb audit: set problem',
|
|
277
|
+
});
|
|
278
|
+
expect(mcpCallWithSessionMock).toHaveBeenCalledWith('chain.updateEntry', {
|
|
279
|
+
entryId: 'BET-200',
|
|
280
|
+
data: { appetite: '6 weeks' },
|
|
281
|
+
changeNote: 'Auto-fix via pb audit: set appetite',
|
|
282
|
+
});
|
|
283
|
+
// Should have rerun the audit (2 mcpCall invocations total)
|
|
284
|
+
expect(mcpCallMock).toHaveBeenCalledTimes(2);
|
|
285
|
+
// Exit code should reflect the rerun result (pass = 0)
|
|
286
|
+
expect(exit.code).toBe(0);
|
|
287
|
+
}));
|
|
288
|
+
it('does not fix when no session is active', withTty(false, async () => {
|
|
289
|
+
mockSession = null;
|
|
290
|
+
mcpCallMock.mockResolvedValue(FAIL_FIXTURE);
|
|
291
|
+
catchExit();
|
|
292
|
+
await expect(runAudit({ entryIds: ['BET-200'], fix: true })).rejects.toThrow('process.exit');
|
|
293
|
+
// Should NOT have called updateEntry
|
|
294
|
+
expect(mcpCallWithSessionMock).not.toHaveBeenCalled();
|
|
295
|
+
// Should still show the result
|
|
296
|
+
const parsed = JSON.parse(stdoutOutput);
|
|
297
|
+
expect(parsed.verdict).toBe('fail');
|
|
298
|
+
}));
|
|
299
|
+
it('skips non-exact fixType gates', withTty(false, async () => {
|
|
300
|
+
const manualFixFixture = {
|
|
301
|
+
...FAIL_FIXTURE,
|
|
302
|
+
gates: [
|
|
303
|
+
{ gate: 'intentional-relations', status: 'fail', blocking: true, detail: '0 relations', fix: 'Add relations manually', fixType: 'manual' },
|
|
304
|
+
{ gate: 'strategic-anchor', status: 'pass', blocking: true, detail: 'OK' },
|
|
305
|
+
],
|
|
306
|
+
};
|
|
307
|
+
mcpCallMock.mockResolvedValue(manualFixFixture);
|
|
308
|
+
catchExit();
|
|
309
|
+
await expect(runAudit({ entryIds: ['BET-200'], fix: true })).rejects.toThrow('process.exit');
|
|
310
|
+
// No exact fixes → no updateEntry calls, no rerun
|
|
311
|
+
expect(mcpCallWithSessionMock).not.toHaveBeenCalled();
|
|
312
|
+
expect(mcpCallMock).toHaveBeenCalledTimes(1);
|
|
313
|
+
}));
|
|
314
|
+
it('stops after one rerun even if issues remain', withTty(false, async () => {
|
|
315
|
+
// Both calls return failing audit (fix didn't resolve everything)
|
|
316
|
+
mcpCallMock
|
|
317
|
+
.mockResolvedValueOnce(FAIL_FIXTURE)
|
|
318
|
+
.mockResolvedValueOnce(FAIL_FIXTURE);
|
|
319
|
+
mcpCallWithSessionMock.mockResolvedValue({ id: 'result-id', warnings: [] });
|
|
320
|
+
const exit = catchExit();
|
|
321
|
+
await expect(runAudit({ entryIds: ['BET-200'], fix: true })).rejects.toThrow('process.exit');
|
|
322
|
+
// Should have run audit exactly 2 times (initial + 1 rerun), not 3
|
|
323
|
+
expect(mcpCallMock).toHaveBeenCalledTimes(2);
|
|
324
|
+
expect(exit.code).toBe(1);
|
|
325
|
+
}));
|
|
326
|
+
});
|
|
327
|
+
describe('runAudit — batch mode', () => {
|
|
328
|
+
it('audits multiple bets sequentially', withTty(false, async () => {
|
|
329
|
+
mcpCallMock
|
|
330
|
+
.mockResolvedValueOnce(PASS_FIXTURE)
|
|
331
|
+
.mockResolvedValueOnce(FAIL_FIXTURE);
|
|
332
|
+
const exit = catchExit();
|
|
333
|
+
await expect(runAudit({ entryIds: ['BET-182', 'BET-200'] })).rejects.toThrow('process.exit');
|
|
334
|
+
// Both auditBet calls should have been made
|
|
335
|
+
expect(mcpCallMock).toHaveBeenCalledWith('chain.auditBet', { entryId: 'BET-182' });
|
|
336
|
+
expect(mcpCallMock).toHaveBeenCalledWith('chain.auditBet', { entryId: 'BET-200' });
|
|
337
|
+
// Exit code should be worst verdict (fail = 1)
|
|
338
|
+
expect(exit.code).toBe(1);
|
|
339
|
+
// Should have batch summary as last line of output
|
|
340
|
+
const lines = stdoutOutput.trim().split('\n');
|
|
341
|
+
const lastLine = lines[lines.length - 1];
|
|
342
|
+
const batchSummary = JSON.parse(lastLine);
|
|
343
|
+
expect(batchSummary.batch).toBe(true);
|
|
344
|
+
expect(batchSummary.count).toBe(2);
|
|
345
|
+
expect(batchSummary.passed).toBe(1);
|
|
346
|
+
expect(batchSummary.failed).toBe(1);
|
|
347
|
+
}));
|
|
348
|
+
it('shows separator between entries in TTY mode', withTty(true, async () => {
|
|
349
|
+
mcpCallMock
|
|
350
|
+
.mockResolvedValueOnce(PASS_FIXTURE)
|
|
351
|
+
.mockResolvedValueOnce(WARN_FIXTURE);
|
|
352
|
+
catchExit();
|
|
353
|
+
await expect(runAudit({ entryIds: ['BET-182', 'BET-201'] })).rejects.toThrow('process.exit');
|
|
354
|
+
// Should have separator
|
|
355
|
+
expect(stdoutOutput).toContain('---');
|
|
356
|
+
// Both entries present
|
|
357
|
+
expect(stdoutOutput).toContain('BET-182');
|
|
358
|
+
expect(stdoutOutput).toContain('BET-201');
|
|
359
|
+
}));
|
|
360
|
+
it('continues after error on one entry', withTty(false, async () => {
|
|
361
|
+
mcpCallMock
|
|
362
|
+
.mockRejectedValueOnce(new Error('Entry "BET-999" not found.'))
|
|
363
|
+
.mockResolvedValueOnce(PASS_FIXTURE);
|
|
364
|
+
const exit = catchExit();
|
|
365
|
+
await expect(runAudit({ entryIds: ['BET-999', 'BET-182'] })).rejects.toThrow('process.exit');
|
|
366
|
+
// Error is worst (3 > 0)
|
|
367
|
+
expect(exit.code).toBe(3);
|
|
368
|
+
// stderr should have the error
|
|
369
|
+
expect(stderrOutput).toContain('BET-999');
|
|
370
|
+
// stdout should have the successful result
|
|
371
|
+
expect(stdoutOutput).toContain('BET-182');
|
|
372
|
+
}));
|
|
373
|
+
});
|
|
374
|
+
describe('runAudit — error handling', () => {
|
|
375
|
+
it('outputs JSON error on pipe when entry not found', withTty(false, async () => {
|
|
376
|
+
mcpCallMock.mockRejectedValue(new Error('Entry "BET-999" not found.'));
|
|
377
|
+
const exit = catchExit();
|
|
378
|
+
await expect(runAudit({ entryIds: ['BET-999'] })).rejects.toThrow('process.exit');
|
|
379
|
+
expect(exit.code).toBe(3);
|
|
380
|
+
const errParsed = JSON.parse(stderrOutput);
|
|
381
|
+
expect(errParsed).toHaveProperty('error');
|
|
382
|
+
expect(errParsed.error).toContain('BET-999');
|
|
383
|
+
expect(errParsed.entryId).toBe('BET-999');
|
|
384
|
+
}));
|
|
385
|
+
it('outputs human error in TTY when entry not found', withTty(true, async () => {
|
|
386
|
+
mcpCallMock.mockRejectedValue(new Error('Entry "BET-999" not found.'));
|
|
387
|
+
const exit = catchExit();
|
|
388
|
+
await expect(runAudit({ entryIds: ['BET-999'] })).rejects.toThrow('process.exit');
|
|
389
|
+
expect(exit.code).toBe(3);
|
|
390
|
+
expect(stderrOutput).toContain('Error auditing BET-999');
|
|
391
|
+
expect(stderrOutput).toContain('not found');
|
|
392
|
+
}));
|
|
393
|
+
});
|
|
394
|
+
//# sourceMappingURL=audit.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit.test.js","sourceRoot":"","sources":["../../src/__tests__/audit.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capture.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/capture.test.ts"],"names":[],"mappings":""}
|