@oneie/claude 0.6.0 → 0.7.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/agents/w1-recon.md +9 -4
- package/agents/w2-decide.md +51 -28
- package/agents/w3-edit.md +70 -78
- package/agents/w4-verify.md +164 -69
- package/commands/browser.md +98 -35
- package/commands/cc-connect.md +6 -0
- package/commands/chat.md +13 -1
- package/commands/close.md +45 -19
- package/commands/create.md +20 -10
- package/commands/db-sync.md +5 -1
- package/commands/deploy.md +174 -87
- package/commands/do-autonomous.md +31 -20
- package/commands/do-improve.md +4 -4
- package/commands/do-show.md +4 -3
- package/commands/do.md +53 -13
- package/commands/go.md +75 -0
- package/commands/improve.md +4 -2
- package/commands/kill.md +6 -8
- package/commands/notify.md +15 -2
- package/commands/oo-push.md +24 -9
- package/commands/rag.md +6 -0
- package/commands/release.md +46 -25
- package/commands/restart.md +5 -4
- package/commands/see.md +45 -35
- package/commands/skill-create.md +38 -5
- package/commands/sync.md +21 -11
- package/hooks/scripts/auto-continue.sh +70 -0
- package/hooks/scripts/branch-pin.sh +85 -0
- package/hooks/scripts/git-add-guard.sh +16 -5
- package/hooks/scripts/post-edit-check.sh +16 -0
- package/hooks/scripts/session-start.sh +13 -8
- package/hooks/scripts/sync-priority-todo.sh +5 -0
- package/package.json +1 -1
- package/rules/api.md +9 -0
- package/rules/design.md +13 -3
- package/rules/documentation.md +30 -71
- package/rules/engine.md +8 -1
- package/rules/ui.md +5 -1
- package/scripts/__pycache__/do-rank.cpython-313.pyc +0 -0
- package/scripts/browser-check.mjs +44 -103
- package/scripts/cc-events-proof.sh +13 -12
- package/scripts/chrome.mjs +381 -0
- package/scripts/do-analyze.sh +109 -4
- package/scripts/do-auto.sh +350 -43
- package/scripts/do-consumer-sweep.sh +72 -0
- package/scripts/do-derives-check.sh +88 -0
- package/scripts/do-fleet.sh +50 -1
- package/scripts/do-killswitch-audit.py +33 -14
- package/scripts/do-promise-lint.sh +150 -4
- package/scripts/do-promise-settle.sh +131 -9
- package/scripts/do-prove.sh +197 -17
- package/scripts/do-rank.py +606 -20
- package/scripts/do-rubric.py +21 -2
- package/scripts/do-signal.sh +157 -17
- package/scripts/do-smoke.sh +9 -0
- package/scripts/do-substrate-check.sh +49 -0
- package/scripts/do-tasks-wire-check.sh +81 -0
- package/scripts/do-tier.sh +90 -5
- package/scripts/do-ui-gate.sh +332 -0
- package/scripts/do-untracked-gate.sh +231 -0
- package/scripts/do-walk.sh +344 -0
- package/scripts/factory-check.sh +747 -0
- package/scripts/factory-repo.sh +1361 -0
- package/scripts/factory-tasks-check.sh +85 -0
- package/scripts/outcome-pull.ts +279 -0
- package/scripts/promise-manifest.mjs +167 -0
- package/scripts/reconcile-allow.txt +5 -0
- package/scripts/rubric-weights.json +64 -0
- package/scripts/spine-canary.sh +20 -0
- package/scripts/typedb-cluster-status.sh +128 -0
- package/scripts/typedb-env.sh +182 -0
- package/scripts/typedb-flap-recorder.sh +85 -0
- package/scripts/typedb-probes/containment-probe.py +88 -0
- package/scripts/typedb-probes/panic-probe-version.py +92 -0
- package/scripts/typedb-probes/panic-probe.py +77 -0
- package/scripts/typedb-scratch.sh +73 -0
- package/scripts/urls-lint.sh +58 -0
- package/scripts/w4-rubric.ts +96 -12
- package/scripts/wf-check.mjs +75 -0
- package/skills/ai-ui/SKILL.md +1 -1
- package/skills/astro/SKILL.md +177 -132
- package/skills/astro/add-content-collection.md +29 -13
- package/skills/astro/check-build.md +19 -13
- package/skills/astro/create-component.md +36 -9
- package/skills/astro/create-page.md +39 -10
- package/skills/astro/optimize-performance.md +36 -8
- package/skills/cli/SKILL.md +254 -220
- package/skills/dev/SKILL.md +1 -1
- package/skills/directory-autofill/SKILL.md +68 -0
- package/skills/docs/SKILL.md +4 -4
- package/skills/mcp/SKILL.md +186 -156
- package/skills/promise-make/SKILL.md +2 -2
- package/skills/puck/SKILL.md +465 -250
- package/skills/react19/SKILL.md +196 -296
- package/skills/reactflow/SKILL.md +387 -412
- package/skills/sdk/SKILL.md +167 -106
- package/skills/shadcn/SKILL.md +245 -201
- package/skills/signal/SKILL.md +5 -0
- package/skills/sui/SKILL.md +6 -1
- package/skills/tutorial/SKILL.md +15 -0
- package/skills/typedb/SKILL.md +427 -217
- package/skills/typedb/examples/python-patterns.py +11 -4
- package/skills/typedb/examples/query-patterns.tql +8 -3
- package/skills/typedb/examples/schema-patterns.tql +4 -2
- package/skills/typedb/reference/migration-2x-3x.md +19 -1
- package/skills/typedb/reference/python-driver.md +17 -1
- package/skills/voice/SKILL.md +117 -0
- package/skills/writer/SKILL.md +29 -12
- package/templates/template-feature.md +26 -1
- package/templates/template-tests.md +4 -0
- package/templates/template-todo.md +65 -10
package/skills/cli/SKILL.md
CHANGED
|
@@ -1,318 +1,352 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cli
|
|
3
|
+
description: Add or change a command in @oneie/cli — the operator CLI shipped as the `oneie` and `one` bins. Use when adding a CLI verb or command group, editing packages/cli/src/*.ts, wiring a command to a receiver through ask(), closing the loop with out(cmd, data), handling --json output, or resolving the API base URL and key. Triggers — "add a CLI command", "new `one` verb", "oneie <group> <verb>", "make the command output JSON", "which host does --api point at", "one fn / one agent / one push is doing X".
|
|
4
|
+
---
|
|
5
|
+
|
|
1
6
|
# CLI verbs — operator commands via @oneie/cli
|
|
2
7
|
|
|
3
|
-
CLI verbs let operators interact with ONE from the terminal.
|
|
8
|
+
CLI verbs let operators interact with ONE from the terminal. Every substrate
|
|
9
|
+
command is a thin wrapper over a receiver — no new HTTP routes.
|
|
4
10
|
|
|
5
11
|
## Structure
|
|
6
12
|
|
|
7
13
|
```
|
|
8
14
|
packages/cli/
|
|
9
15
|
├── src/
|
|
10
|
-
│ ├──
|
|
11
|
-
│ ├──
|
|
12
|
-
│ │
|
|
13
|
-
│ │
|
|
14
|
-
│ │
|
|
15
|
-
│ │
|
|
16
|
-
│
|
|
17
|
-
│
|
|
18
|
-
│ │
|
|
19
|
-
│ │
|
|
20
|
-
│
|
|
21
|
-
|
|
16
|
+
│ ├── index.ts # builds `program`, addCommand/group
|
|
17
|
+
│ ├── <group>.ts # one file per group → <group>Cmd()
|
|
18
|
+
│ │ # agent · skill · auth · dev · group
|
|
19
|
+
│ │ # social · connect · broadcast · chat
|
|
20
|
+
│ │ # links · staff · wallet · push · fn
|
|
21
|
+
│ │ # deploy · ship · workflow · plugin …
|
|
22
|
+
│ ├── substrate.ts # 6 verbs + dim reads
|
|
23
|
+
│ ├── lib/
|
|
24
|
+
│ │ ├── client.ts # resolveBase/Key, out, jsonMode
|
|
25
|
+
│ │ └── api-path.ts # askPath() — gateway vs web
|
|
26
|
+
│ └── templates/
|
|
27
|
+
└── tests/ # vitest — registration + behaviour
|
|
22
28
|
```
|
|
23
29
|
|
|
30
|
+
There is no `src/cli.ts` and no `src/commands/` directory — a command group is
|
|
31
|
+
one flat file at `src/<group>.ts`. Bins: `oneie` and `one`, both
|
|
32
|
+
`dist/src/index.js`. Runtime deps are exactly two: `commander` + `@oneie/sdk`.
|
|
33
|
+
|
|
24
34
|
## Pattern: Adding a CLI verb
|
|
25
35
|
|
|
26
36
|
### 1. Define the command shape
|
|
27
37
|
|
|
28
38
|
```typescript
|
|
29
|
-
// packages/cli/src/
|
|
30
|
-
import { Command } from 'commander'
|
|
31
|
-
import {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
39
|
+
// packages/cli/src/links.ts
|
|
40
|
+
import { Command } from 'commander'
|
|
41
|
+
import { authHeaders, resolveBase } from './lib/client.js'
|
|
42
|
+
import { askPath } from './lib/api-path.js'
|
|
43
|
+
|
|
44
|
+
const DEFAULT_API = resolveBase({}, 'https://api.one.ie')
|
|
45
|
+
|
|
46
|
+
async function ask(api: string, receiver: string, data: unknown): Promise<unknown> {
|
|
47
|
+
const res = await fetch(askPath(api.replace(/\/$/, ''), receiver), {
|
|
48
|
+
method: 'POST',
|
|
49
|
+
headers: authHeaders(),
|
|
50
|
+
body: JSON.stringify({ data }),
|
|
51
|
+
})
|
|
52
|
+
if (!res.ok) {
|
|
53
|
+
process.stderr.write(`POST /api/ask/${receiver} → ${res.status}\n`)
|
|
54
|
+
process.exit(1)
|
|
55
|
+
}
|
|
56
|
+
return res.json()
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function linksCmd(): Command {
|
|
60
|
+
const cmd = new Command('links').description('Create actor-bound tracked links')
|
|
61
|
+
|
|
62
|
+
cmd
|
|
63
|
+
.command('create <actorId>')
|
|
64
|
+
.description('Create a tracked link bound to a contact')
|
|
65
|
+
.option('--to <path>', "Destination path, e.g. '/pricing'", '/')
|
|
66
|
+
.option('--expires <days>', 'Link TTL in days (omit = never)')
|
|
67
|
+
.option('--api <url>', 'API base URL', DEFAULT_API)
|
|
68
|
+
.action(async (actorId: string, opts: { to: string; expires?: string; api: string }) => {
|
|
69
|
+
out(await ask(opts.api, 'links:create', {
|
|
70
|
+
actorId,
|
|
71
|
+
destination: opts.to,
|
|
72
|
+
expiresInDays: opts.expires ? Number(opts.expires) : undefined,
|
|
73
|
+
}))
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
return cmd
|
|
63
77
|
}
|
|
64
78
|
```
|
|
65
79
|
|
|
66
|
-
|
|
80
|
+
**Rules:**
|
|
81
|
+
- Build the path with `askPath(base, receiver)`. The gateway (`api.one.ie`)
|
|
82
|
+
serves `/ask/<receiver>`; `one.ie/web` serves `/api/ask/<receiver>`. Hardcoding
|
|
83
|
+
either shape 404s against the other host
|
|
84
|
+
- `--api` default is per-module, not global. Verified by
|
|
85
|
+
`grep -n "api.one.ie\|https://one.ie" packages/cli/src/*.ts`: gateway-facing
|
|
86
|
+
(`https://api.one.ie`) are `broadcast`, `links`, `substrate`, `wallet`,
|
|
87
|
+
`catalog`, `trade`, `fn`, `coordinate`, `client`, `push`, `setup`; web-facing
|
|
88
|
+
(`https://one.ie`) are `chat`, `connect`, `group`, `social`, `trail`, `staff`,
|
|
89
|
+
`auth`, `init`, `onboard`, `status`, `skill`, `plugin`. Read the module's own
|
|
90
|
+
`DEFAULT_API` before assuming — some call `resolveBase({}, fallback)` and some
|
|
91
|
+
read `ONEIE_BASE_URL`/`ONE_API_URL` inline
|
|
92
|
+
- The option name determines the property: `--to` reads as `opts.to`,
|
|
93
|
+
`--batch-size` as `opts.batchSize`. Map to the receiver's field names explicitly
|
|
94
|
+
- Target an existing receiver or `/api/*` route — never add a new endpoint
|
|
95
|
+
|
|
96
|
+
### 2. Close the loop with `out()`
|
|
97
|
+
|
|
98
|
+
`out(cmd, data)` from `lib/client.ts` is the canonical closer: human-readable
|
|
99
|
+
`ok k=v k=v` by default, one line of JSON under `--json`, `ok: false` routed to
|
|
100
|
+
stderr with exit code 1.
|
|
67
101
|
|
|
68
102
|
```typescript
|
|
69
|
-
|
|
70
|
-
import { Command } from 'commander';
|
|
71
|
-
import { createReadMemoryCommand } from './read';
|
|
72
|
-
import { createWriteMemoryCommand } from './write';
|
|
103
|
+
import { out, resolveBase, resolveKey } from './lib/client.js'
|
|
73
104
|
|
|
74
|
-
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// packages/cli/src/commands/index.ts
|
|
85
|
-
export { createMemoryCommand } from './memory';
|
|
86
|
-
export { createTaskCommand } from './task';
|
|
87
|
-
// other commands
|
|
105
|
+
.action(async (opts: { csv: string; api: string }) => {
|
|
106
|
+
const key = resolveKey()
|
|
107
|
+
if (!key) {
|
|
108
|
+
out(cmd, { ok: false, error: 'no API key — set ONE_API_KEY or run: oneie auth login' })
|
|
109
|
+
return
|
|
110
|
+
}
|
|
111
|
+
out(cmd, { ok: true, created: 12, skipped: 3 })
|
|
112
|
+
})
|
|
88
113
|
```
|
|
89
114
|
|
|
90
|
-
|
|
115
|
+
`jsonMode(cmd)` walks `cmd.parent` to the root, so `--json` works wherever the
|
|
116
|
+
operator puts it. Some older groups (`links`, `broadcast`) still use a local
|
|
117
|
+
`out(data)` that always pretty-prints JSON — new commands use `out(cmd, data)`.
|
|
91
118
|
|
|
92
|
-
|
|
93
|
-
// packages/cli/src/cli.ts
|
|
94
|
-
import { Command } from 'commander';
|
|
95
|
-
import { createMemoryCommand } from './commands';
|
|
119
|
+
### 3. Register the command
|
|
96
120
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
.description('ONE operator CLI')
|
|
101
|
-
.version('1.0.0');
|
|
121
|
+
```typescript
|
|
122
|
+
// packages/cli/src/index.ts
|
|
123
|
+
import { linksCmd } from './links.js'
|
|
102
124
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
125
|
+
const program = new Command()
|
|
126
|
+
.name('oneie')
|
|
127
|
+
.description('ONE — agent CLI')
|
|
128
|
+
.version(pkg.version)
|
|
129
|
+
.option('--json', 'Output structured JSON')
|
|
106
130
|
|
|
107
|
-
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// bin/one (executable)
|
|
111
|
-
#!/usr/bin/env node
|
|
112
|
-
const cli = createCli();
|
|
113
|
-
cli.parse(process.argv);
|
|
131
|
+
program.addCommand(linksCmd())
|
|
114
132
|
```
|
|
115
133
|
|
|
134
|
+
Groups that register several top-level commands export a `<group>Commands(program)`
|
|
135
|
+
function instead (`substrateCommands`, `catalogCommands`, `tradeCommands`,
|
|
136
|
+
`coordinateCommands`). Relative imports carry the `.js` extension — ESM.
|
|
137
|
+
|
|
116
138
|
### 4. Test the command
|
|
117
139
|
|
|
140
|
+
Registration tests are cheap and catch the common regression (a subcommand
|
|
141
|
+
silently dropped):
|
|
142
|
+
|
|
118
143
|
```typescript
|
|
119
|
-
// packages/cli/
|
|
120
|
-
import {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
const
|
|
126
|
-
expect(
|
|
127
|
-
})
|
|
128
|
-
|
|
129
|
-
it('shows error when group not found', () => {
|
|
130
|
-
expect(() => {
|
|
131
|
-
execSync('one memory read nonexistent');
|
|
132
|
-
}).toThrow();
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
it('supports multiple output formats', () => {
|
|
136
|
-
const json = execSync('one memory read group-123 --format json').toString();
|
|
137
|
-
const yaml = execSync('one memory read group-123 --format yaml').toString();
|
|
138
|
-
expect(json).toContain('{');
|
|
139
|
-
expect(yaml).not.toContain('{');
|
|
140
|
-
});
|
|
141
|
-
});
|
|
144
|
+
// packages/cli/tests/workflow.test.ts
|
|
145
|
+
import { describe, it, expect } from 'vitest'
|
|
146
|
+
import { workflowCmd } from '../src/workflow.js'
|
|
147
|
+
|
|
148
|
+
describe('workflow CLI registration', () => {
|
|
149
|
+
it('registers list/pull/push/run/validate/resolve/logs subcommands', () => {
|
|
150
|
+
const names = workflowCmd().commands.map((c) => c.name()).sort()
|
|
151
|
+
expect(names).toEqual(['list', 'logs', 'pull', 'push', 'resolve', 'run', 'validate'])
|
|
152
|
+
})
|
|
153
|
+
})
|
|
142
154
|
```
|
|
143
155
|
|
|
156
|
+
**Rules:**
|
|
157
|
+
- `bun run test` in `packages/cli` (vitest)
|
|
158
|
+
- Import the `<group>Cmd()` factory and assert on the commander tree — don't
|
|
159
|
+
`execSync` the bin; the built `dist/` may be stale and the call hits the network
|
|
160
|
+
- For behaviour, call the action's collaborators directly (see
|
|
161
|
+
`tests/doctor.test.ts`, `tests/setup-keyless.test.ts`)
|
|
162
|
+
|
|
144
163
|
## Naming conventions
|
|
145
164
|
|
|
146
|
-
**Command structure:** `one {
|
|
147
|
-
-
|
|
148
|
-
-
|
|
149
|
-
-
|
|
150
|
-
-
|
|
151
|
-
-
|
|
165
|
+
**Command structure:** `one {group} {verb} [args]`
|
|
166
|
+
- Correct: `one links create <actorId>`
|
|
167
|
+
- Correct: `one broadcast send <id>`
|
|
168
|
+
- Correct: `one workflow pull <id> --slug acme`
|
|
169
|
+
- Wrong: `one -l create-link` (unclear)
|
|
170
|
+
- Wrong: `one links --create <actorId>` (verb is an option, not a subcommand)
|
|
171
|
+
|
|
172
|
+
Single-purpose groups stay flat as top-level commands — `one whoami`, `one doctor`,
|
|
173
|
+
`one status`, `one trail <tags>`, `one signal <receiver>`.
|
|
152
174
|
|
|
153
175
|
**Verb names:** imperative, no "get"
|
|
154
|
-
-
|
|
155
|
-
-
|
|
176
|
+
- Correct: `create`, `list`, `send`, `pull`, `push`, `run`, `validate`, `approve`
|
|
177
|
+
- Wrong: `get-broadcast`, `CREATE_LINK`, `bc_list`
|
|
156
178
|
|
|
157
179
|
**Arguments and options:**
|
|
158
|
-
- Arguments: positional, required, no dashes
|
|
159
|
-
|
|
160
|
-
-
|
|
161
|
-
|
|
180
|
+
- Arguments: positional, required, no dashes — `one broadcast send <id>`
|
|
181
|
+
- Options: named, optional, with dashes — `--to /pricing`, `--limit 20`
|
|
182
|
+
- `--api <url>` and `--key <k>` are the two conventional overrides; both fall
|
|
183
|
+
through to `resolveBase()` / `resolveKey()` when omitted
|
|
162
184
|
|
|
163
185
|
## Command categories
|
|
164
186
|
|
|
165
187
|
| Category | Verbs | Purpose |
|
|
166
188
|
|----------|-------|---------|
|
|
167
|
-
| **Read** | `
|
|
168
|
-
| **Create** | `create`, `
|
|
169
|
-
| **Update** | `
|
|
170
|
-
| **Delete** | `
|
|
171
|
-
| **Execute** | `send`, `
|
|
189
|
+
| **Read** | `list`, `get`, `status`, `whoami`, `doctor` | Display data without side effects |
|
|
190
|
+
| **Create** | `create`, `new`, `init`, `add`, `scaffold` | Create new entity |
|
|
191
|
+
| **Update** | `push`, `set`, `rename`, `refresh` | Modify existing entity |
|
|
192
|
+
| **Delete** | `unpublish`, `unimport`, `logout` | Remove entity |
|
|
193
|
+
| **Execute** | `send`, `run`, `publish`, `deploy`, `eval` | Action with side effects |
|
|
172
194
|
|
|
173
195
|
## Output format
|
|
174
196
|
|
|
175
|
-
**Default (
|
|
197
|
+
**Default (human):** one `ok` line of key=value pairs, from `out(cmd, data)`
|
|
176
198
|
|
|
177
199
|
```
|
|
178
|
-
$ one
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
task-2 Deploy v1.2 in-progress
|
|
182
|
-
task-3 Write docs done
|
|
200
|
+
$ one group bulk-create --csv clients.csv
|
|
201
|
+
batch 1/1 created=12 skipped=3
|
|
202
|
+
ok total_rows=15 created=12 duplicates=3 batches=1 plan="studio" segment="ICP-1" dry_run=false
|
|
183
203
|
```
|
|
184
204
|
|
|
185
|
-
|
|
205
|
+
Values are `JSON.stringify`d, so strings keep their quotes and `ok` itself is
|
|
206
|
+
dropped from the human line.
|
|
186
207
|
|
|
187
|
-
|
|
188
|
-
$ one task list --format json
|
|
189
|
-
[
|
|
190
|
-
{"id": "task-1", "title": "Review PR", "status": "open"},
|
|
191
|
-
{"id": "task-2", "title": "Deploy v1.2", "status": "in-progress"},
|
|
192
|
-
{"id": "task-3", "title": "Write docs", "status": "done"}
|
|
193
|
-
]
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
**CSV:** for spreadsheet import
|
|
208
|
+
**`--json`:** one line of structured JSON, suitable for piping
|
|
197
209
|
|
|
198
210
|
```
|
|
199
|
-
$ one
|
|
200
|
-
|
|
201
|
-
task-1,Review PR,open
|
|
202
|
-
task-2,Deploy v1.2,in-progress
|
|
203
|
-
task-3,Write docs,done
|
|
211
|
+
$ one group bulk-create --csv clients.csv --json
|
|
212
|
+
{"ok":true,"total_rows":15,"created":12,"duplicates":3,"batches":1,"plan":"studio","segment":"ICP-1","dry_run":false}
|
|
204
213
|
```
|
|
205
214
|
|
|
215
|
+
`--json` is a global option declared on `program`, and `jsonMode()` finds it at
|
|
216
|
+
any depth. There is no `--format` flag and no YAML or CSV output — `--json` plus
|
|
217
|
+
`jq` is the whole contract. An uncaught error also honours it: `index.ts` prints
|
|
218
|
+
`{"ok":false,"error":"…"}` to stdout under `--json`, the message to stderr
|
|
219
|
+
otherwise, and exits 1.
|
|
220
|
+
|
|
206
221
|
## Anti-patterns
|
|
207
222
|
|
|
208
|
-
|
|
223
|
+
**Verb as an option**
|
|
209
224
|
```bash
|
|
210
225
|
# WRONG
|
|
211
|
-
one
|
|
212
|
-
one memory --write group-123 "content"
|
|
226
|
+
one links --create u-123
|
|
213
227
|
```
|
|
214
228
|
**Fix:** Verbs are subcommands, not options.
|
|
215
229
|
```bash
|
|
216
|
-
one
|
|
217
|
-
one memory write group-123 --content "content"
|
|
230
|
+
one links create u-123 --to /pricing
|
|
218
231
|
```
|
|
219
232
|
|
|
220
|
-
|
|
233
|
+
**Hardcoding the ask path**
|
|
221
234
|
```typescript
|
|
222
|
-
// WRONG
|
|
223
|
-
|
|
224
|
-
const memory = await client.memory(groupId);
|
|
225
|
-
console.log(memory); // crashes if error
|
|
226
|
-
});
|
|
235
|
+
// WRONG — 404s whenever --api points at the gateway
|
|
236
|
+
await fetch(`${api}/api/ask/links:create`, { … })
|
|
227
237
|
```
|
|
228
|
-
**Fix:**
|
|
238
|
+
**Fix:** `askPath(base, 'links:create')` picks the form by hostname.
|
|
239
|
+
|
|
240
|
+
**Hardcoding the base URL or reading the key inline**
|
|
229
241
|
```typescript
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
console.log(memory);
|
|
234
|
-
} catch (error) {
|
|
235
|
-
console.error(`Error: ${error.message}`);
|
|
236
|
-
process.exit(1);
|
|
237
|
-
}
|
|
238
|
-
});
|
|
242
|
+
// WRONG
|
|
243
|
+
const api = 'https://one.ie'
|
|
244
|
+
const key = process.env.ONE_API_KEY
|
|
239
245
|
```
|
|
246
|
+
**Fix:** `resolveBase(opts, fallback)` and `resolveKey(opts)` — they encode the
|
|
247
|
+
`--flag > canonical env > legacy env > ~/.config/oneie/key` ladder.
|
|
240
248
|
|
|
241
|
-
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
|
|
249
|
+
**Silent return**
|
|
250
|
+
```typescript
|
|
251
|
+
// WRONG
|
|
252
|
+
program.action(async (id) => {
|
|
253
|
+
const r = await ask(api, 'broadcast:send', { broadcastId: id })
|
|
254
|
+
console.log(r) // no ok/error shape, no exit code, breaks --json
|
|
255
|
+
})
|
|
245
256
|
```
|
|
246
|
-
**Fix:**
|
|
257
|
+
**Fix:** Close the loop with `out(cmd, { ok, ...data })` — the locked closed-loop rule.
|
|
247
258
|
|
|
248
|
-
|
|
259
|
+
**No help text**
|
|
249
260
|
```typescript
|
|
250
261
|
// WRONG
|
|
251
|
-
new Command('
|
|
252
|
-
.argument('<
|
|
253
|
-
.action(async (
|
|
262
|
+
new Command('create')
|
|
263
|
+
.argument('<actorId>')
|
|
264
|
+
.action(async (actorId) => { /* … */ })
|
|
254
265
|
```
|
|
255
|
-
**Fix:** Add description and option
|
|
266
|
+
**Fix:** Add a description to the command and to every argument and option.
|
|
256
267
|
```typescript
|
|
257
|
-
new Command('
|
|
258
|
-
.description('
|
|
259
|
-
.argument('<
|
|
260
|
-
.option('
|
|
261
|
-
.action(async (groupId, options) => { ... });
|
|
268
|
+
new Command('create')
|
|
269
|
+
.description('Create a tracked link bound to a contact')
|
|
270
|
+
.argument('<actorId>', 'Contact the link is bound to')
|
|
271
|
+
.option('--to <path>', "Destination path, e.g. '/pricing'", '/')
|
|
262
272
|
```
|
|
263
273
|
|
|
274
|
+
**Adding a dependency**
|
|
275
|
+
```typescript
|
|
276
|
+
// WRONG — breaks `npm i -g @oneie/cli` / `npx oneie`
|
|
277
|
+
import YAML from 'yaml'
|
|
278
|
+
import { z } from 'zod'
|
|
279
|
+
```
|
|
280
|
+
**Fix:** Runtime deps are `commander` + `@oneie/sdk`, full stop. Hand-rolled
|
|
281
|
+
YAML/Markdown parsers live in the SDK; `@oneie/evals` is a devDependency on purpose.
|
|
282
|
+
|
|
264
283
|
## Composability rules
|
|
265
284
|
|
|
266
|
-
**New verb
|
|
285
|
+
**New verb wraps a receiver:**
|
|
267
286
|
```typescript
|
|
268
|
-
// GOOD —
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
});
|
|
277
|
-
}
|
|
287
|
+
// GOOD — the receiver owns authority, validation, and persistence
|
|
288
|
+
cmd
|
|
289
|
+
.command('list')
|
|
290
|
+
.description('List broadcasts for the workspace')
|
|
291
|
+
.option('--limit <n>', 'Max results', '20')
|
|
292
|
+
.action(async (opts: { limit: string; api: string }) => {
|
|
293
|
+
out(await ask(opts.api, 'broadcast:list', { limit: Number(opts.limit) }))
|
|
294
|
+
})
|
|
278
295
|
```
|
|
279
296
|
|
|
280
|
-
**New verb
|
|
297
|
+
**New verb composes two receivers:**
|
|
281
298
|
```typescript
|
|
282
|
-
// GOOD —
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
const memory = await client.memory(groupId);
|
|
289
|
-
// Analysis is operator-specific, not SDK
|
|
290
|
-
const sentiment = analyzeSentiment(memory.content);
|
|
291
|
-
console.log(`Memory sentiment: ${sentiment}`);
|
|
292
|
-
});
|
|
299
|
+
// GOOD — segment preview needs the definition, not the id, so the CLI
|
|
300
|
+
// fetches it first and fails loudly if it is missing
|
|
301
|
+
const got = await ask(opts.api, 'segment:get', { id }) as { segment?: { definition?: unknown } }
|
|
302
|
+
if (!got.segment) {
|
|
303
|
+
process.stderr.write(`segment:get returned no segment for id=${id}\n`)
|
|
304
|
+
process.exit(1)
|
|
293
305
|
}
|
|
306
|
+
out(await ask(opts.api, 'segment:preview', { definition: got.segment.definition }))
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
**New verb is generated from a catalog:**
|
|
310
|
+
```typescript
|
|
311
|
+
// GOOD — `one fn list` / `one fn run <name>` enumerate FN_ALLOWLIST from
|
|
312
|
+
// @oneie/sdk/fn-allowlist (20 entries today) and route through ask('fn:run').
|
|
313
|
+
// Allowlisting a fun there reaches web, MCP, CLI, and channels in one edit.
|
|
294
314
|
```
|
|
295
315
|
|
|
296
316
|
## Piping and composability
|
|
297
317
|
|
|
298
|
-
|
|
318
|
+
Commands that emit JSON chain through `jq`. Receiver wrappers print the `/api/ask`
|
|
319
|
+
envelope verbatim — `{ outcome, result, signalId, receiver }` — so the receiver's
|
|
320
|
+
own response sits one level down, under `.result`:
|
|
299
321
|
|
|
300
322
|
```bash
|
|
301
|
-
# List
|
|
302
|
-
one
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
one task list --format json | jq '.[] | select(.status == "open")' | jq -s . | one format-csv
|
|
323
|
+
# List broadcasts, keep the drafts, send each one
|
|
324
|
+
one ask broadcast:list --data '{"workspace":"acme","limit":50}' \
|
|
325
|
+
| jq -r '.result.broadcasts[] | select(.status=="draft") | .id' \
|
|
326
|
+
| xargs -I {} one broadcast send {}
|
|
306
327
|
```
|
|
307
328
|
|
|
329
|
+
`validateReceiver` strict-parses the payload against the receiver's zod `request`
|
|
330
|
+
before dispatch, so every required field must be in `--data` — omitting
|
|
331
|
+
`workspace` here is a 400, not a default.
|
|
332
|
+
|
|
333
|
+
Check the group's own `out()` before writing a pipeline: `out(cmd, data)` gives
|
|
334
|
+
one line under `--json` and `ok k=v` otherwise, the local `out(data)` in `links`
|
|
335
|
+
and `broadcast` pretty-prints JSON either way, and a few commands (`whoami`,
|
|
336
|
+
`doctor`) print fixed human lines with no JSON mode at all.
|
|
337
|
+
|
|
308
338
|
**Rules:**
|
|
309
|
-
- Default output is human-readable (
|
|
310
|
-
- `--
|
|
311
|
-
-
|
|
312
|
-
|
|
339
|
+
- Default output is human-readable (`ok k=v`); `--json` is opt-in
|
|
340
|
+
- `--json` output is valid JSON — parseable by `jq`
|
|
341
|
+
- Errors go to stderr with exit code 1; under `--json` the error object goes to
|
|
342
|
+
stdout so a pipeline can read it
|
|
343
|
+
- Never print a secret. `one wallet keygen` prints once and never writes a file
|
|
344
|
+
without `--yes-i-accept-plaintext-file`; `one connect` never echoes the token
|
|
313
345
|
|
|
314
346
|
## See also
|
|
315
347
|
|
|
316
|
-
- `packages/cli/CLAUDE.md` —
|
|
317
|
-
- `packages/
|
|
318
|
-
- `
|
|
348
|
+
- `packages/cli/CLAUDE.md` — the full command map, conventions, and distribution
|
|
349
|
+
- `packages/cli/src/lib/client.ts` — `resolveBase` / `resolveKey` / `out` / `jsonMode`
|
|
350
|
+
- `packages/sdk/src/receivers.ts` — receiver registry (every substrate verb wraps one)
|
|
351
|
+
- `text/cli.md` — the promise: who this CLI is for
|
|
352
|
+
- `text/cli-reference.md` — the command reference written for external readers
|
package/skills/dev/SKILL.md
CHANGED
|
@@ -42,7 +42,7 @@ lsof -i :4321
|
|
|
42
42
|
### Kill existing server
|
|
43
43
|
|
|
44
44
|
```bash
|
|
45
|
-
pkill -f "astro dev"
|
|
45
|
+
lsof -ti:4321 | xargs kill # port-scoped — a bare `pkill -f "astro dev"` kills every Astro on the machine, including other projects and sessions
|
|
46
46
|
```
|
|
47
47
|
|
|
48
48
|
### Run on different port
|