@productbrain/cli 0.1.0-beta.30 → 0.1.0-beta.34
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 +62 -178
- package/dist/__tests__/capture.test.js +2 -11
- package/dist/__tests__/capture.test.js.map +1 -1
- package/dist/__tests__/config.test.d.ts +8 -0
- package/dist/__tests__/config.test.d.ts.map +1 -0
- package/dist/__tests__/config.test.js +166 -0
- package/dist/__tests__/config.test.js.map +1 -0
- package/dist/__tests__/constants.test.js +1 -1
- package/dist/__tests__/constants.test.js.map +1 -1
- package/dist/__tests__/constellation.test.js +2 -8
- package/dist/__tests__/constellation.test.js.map +1 -1
- package/dist/__tests__/errors.test.d.ts +2 -0
- package/dist/__tests__/errors.test.d.ts.map +1 -0
- package/dist/__tests__/errors.test.js +117 -0
- package/dist/__tests__/errors.test.js.map +1 -0
- package/dist/__tests__/fields.test.js +14 -14
- package/dist/__tests__/fields.test.js.map +1 -1
- package/dist/__tests__/glossary.test.d.ts +2 -0
- package/dist/__tests__/glossary.test.d.ts.map +1 -0
- package/dist/__tests__/glossary.test.js +32 -0
- package/dist/__tests__/glossary.test.js.map +1 -0
- package/dist/__tests__/handshake.test.js +9 -17
- package/dist/__tests__/handshake.test.js.map +1 -1
- package/dist/__tests__/init.test.d.ts +7 -0
- package/dist/__tests__/init.test.d.ts.map +1 -0
- package/dist/__tests__/init.test.js +146 -0
- package/dist/__tests__/init.test.js.map +1 -0
- package/dist/__tests__/login.test.js +29 -30
- package/dist/__tests__/login.test.js.map +1 -1
- package/dist/__tests__/onboarding.test.d.ts +6 -0
- package/dist/__tests__/onboarding.test.d.ts.map +1 -0
- package/dist/__tests__/onboarding.test.js +199 -0
- package/dist/__tests__/onboarding.test.js.map +1 -0
- package/dist/__tests__/profiles.test.d.ts +2 -0
- package/dist/__tests__/profiles.test.d.ts.map +1 -0
- package/dist/__tests__/profiles.test.js +168 -0
- package/dist/__tests__/profiles.test.js.map +1 -0
- package/dist/__tests__/promote.test.js +4 -16
- package/dist/__tests__/promote.test.js.map +1 -1
- package/dist/__tests__/prompts.test.d.ts +6 -0
- package/dist/__tests__/prompts.test.d.ts.map +1 -0
- package/dist/__tests__/prompts.test.js +146 -0
- package/dist/__tests__/prompts.test.js.map +1 -0
- package/dist/__tests__/proposals.test.js +6 -29
- package/dist/__tests__/proposals.test.js.map +1 -1
- package/dist/__tests__/relate.test.js +6 -23
- package/dist/__tests__/relate.test.js.map +1 -1
- package/dist/__tests__/runner.test.js +19 -15
- package/dist/__tests__/runner.test.js.map +1 -1
- package/dist/__tests__/session.test.js +2 -8
- package/dist/__tests__/session.test.js.map +1 -1
- package/dist/__tests__/setup.test.js +39 -25
- package/dist/__tests__/setup.test.js.map +1 -1
- package/dist/__tests__/spinner-labels.test.d.ts +2 -0
- package/dist/__tests__/spinner-labels.test.d.ts.map +1 -0
- package/dist/__tests__/spinner-labels.test.js +23 -0
- package/dist/__tests__/spinner-labels.test.js.map +1 -0
- package/dist/__tests__/update.test.js +27 -61
- package/dist/__tests__/update.test.js.map +1 -1
- package/dist/__tests__/workspace.test.d.ts +2 -0
- package/dist/__tests__/workspace.test.d.ts.map +1 -0
- package/dist/__tests__/workspace.test.js +308 -0
- package/dist/__tests__/workspace.test.js.map +1 -0
- package/dist/commands/accept.d.ts.map +1 -1
- package/dist/commands/accept.js +6 -2
- package/dist/commands/accept.js.map +1 -1
- package/dist/commands/brief.d.ts.map +1 -1
- package/dist/commands/brief.js +6 -1
- package/dist/commands/brief.js.map +1 -1
- package/dist/commands/capture.d.ts.map +1 -1
- package/dist/commands/capture.js +20 -12
- package/dist/commands/capture.js.map +1 -1
- package/dist/commands/chain-walk.d.ts.map +1 -1
- package/dist/commands/chain-walk.js +6 -1
- package/dist/commands/chain-walk.js.map +1 -1
- package/dist/commands/changes.d.ts.map +1 -1
- package/dist/commands/changes.js +6 -1
- package/dist/commands/changes.js.map +1 -1
- package/dist/commands/codex-prep.d.ts.map +1 -1
- package/dist/commands/codex-prep.js +6 -2
- package/dist/commands/codex-prep.js.map +1 -1
- package/dist/commands/collections.d.ts.map +1 -1
- package/dist/commands/collections.js +6 -2
- package/dist/commands/collections.js.map +1 -1
- package/dist/commands/constellation.d.ts.map +1 -1
- package/dist/commands/constellation.js +6 -1
- package/dist/commands/constellation.js.map +1 -1
- package/dist/commands/context.d.ts.map +1 -1
- package/dist/commands/context.js +6 -1
- package/dist/commands/context.js.map +1 -1
- package/dist/commands/doctor.d.ts +9 -2
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +125 -28
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/doctor.test.d.ts +3 -1
- package/dist/commands/doctor.test.d.ts.map +1 -1
- package/dist/commands/doctor.test.js +206 -10
- package/dist/commands/doctor.test.js.map +1 -1
- package/dist/commands/fields.d.ts.map +1 -1
- package/dist/commands/fields.js +6 -2
- package/dist/commands/fields.js.map +1 -1
- package/dist/commands/get.d.ts.map +1 -1
- package/dist/commands/get.js +11 -3
- package/dist/commands/get.js.map +1 -1
- package/dist/commands/handshake.d.ts.map +1 -1
- package/dist/commands/handshake.js +21 -22
- package/dist/commands/handshake.js.map +1 -1
- package/dist/commands/ingest.d.ts.map +1 -1
- package/dist/commands/ingest.js +11 -3
- package/dist/commands/ingest.js.map +1 -1
- package/dist/commands/init.d.ts +14 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +117 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +32 -20
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/profile.d.ts +24 -0
- package/dist/commands/profile.d.ts.map +1 -0
- package/dist/commands/profile.js +82 -0
- package/dist/commands/profile.js.map +1 -0
- package/dist/commands/promote.d.ts.map +1 -1
- package/dist/commands/promote.js +22 -7
- package/dist/commands/promote.js.map +1 -1
- package/dist/commands/reject.d.ts.map +1 -1
- package/dist/commands/reject.js +11 -5
- package/dist/commands/reject.js.map +1 -1
- package/dist/commands/relate.d.ts.map +1 -1
- package/dist/commands/relate.js +21 -10
- package/dist/commands/relate.js.map +1 -1
- package/dist/commands/session.d.ts.map +1 -1
- package/dist/commands/session.js +16 -6
- package/dist/commands/session.js.map +1 -1
- package/dist/commands/setup.d.ts +1 -2
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +17 -38
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +45 -27
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/verify.d.ts.map +1 -1
- package/dist/commands/verify.js +11 -5
- package/dist/commands/verify.js.map +1 -1
- package/dist/commands/workspace.d.ts +41 -0
- package/dist/commands/workspace.d.ts.map +1 -0
- package/dist/commands/workspace.js +239 -0
- package/dist/commands/workspace.js.map +1 -0
- package/dist/formatters/promote.d.ts +1 -0
- package/dist/formatters/promote.d.ts.map +1 -1
- package/dist/formatters/promote.js +1 -0
- package/dist/formatters/promote.js.map +1 -1
- package/dist/index.js +328 -299
- package/dist/index.js.map +1 -1
- package/dist/lib/client.d.ts +4 -2
- package/dist/lib/client.d.ts.map +1 -1
- package/dist/lib/client.js +143 -68
- package/dist/lib/client.js.map +1 -1
- package/dist/lib/config.d.ts +63 -4
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +230 -36
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/constants.d.ts +1 -1
- package/dist/lib/constants.d.ts.map +1 -1
- package/dist/lib/constants.js +1 -1
- package/dist/lib/constants.js.map +1 -1
- package/dist/lib/errors.d.ts +58 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/errors.js +67 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/format.d.ts +10 -0
- package/dist/lib/format.d.ts.map +1 -0
- package/dist/lib/format.js +27 -0
- package/dist/lib/format.js.map +1 -0
- package/dist/lib/glossary.d.ts +19 -0
- package/dist/lib/glossary.d.ts.map +1 -0
- package/dist/lib/glossary.js +53 -0
- package/dist/lib/glossary.js.map +1 -0
- package/dist/lib/onboarding.d.ts +19 -0
- package/dist/lib/onboarding.d.ts.map +1 -0
- package/dist/lib/onboarding.js +373 -0
- package/dist/lib/onboarding.js.map +1 -0
- package/dist/lib/profiles.d.ts +34 -0
- package/dist/lib/profiles.d.ts.map +1 -0
- package/dist/lib/profiles.js +173 -0
- package/dist/lib/profiles.js.map +1 -0
- package/dist/lib/prompts.d.ts +38 -0
- package/dist/lib/prompts.d.ts.map +1 -0
- package/dist/lib/prompts.js +90 -0
- package/dist/lib/prompts.js.map +1 -0
- package/dist/lib/runner.d.ts +2 -0
- package/dist/lib/runner.d.ts.map +1 -1
- package/dist/lib/runner.js +21 -7
- package/dist/lib/runner.js.map +1 -1
- package/dist/lib/spinner.d.ts +27 -0
- package/dist/lib/spinner.d.ts.map +1 -0
- package/dist/lib/spinner.js +76 -0
- package/dist/lib/spinner.js.map +1 -0
- package/dist/lib/spinner.test.d.ts +2 -0
- package/dist/lib/spinner.test.d.ts.map +1 -0
- package/dist/lib/spinner.test.js +39 -0
- package/dist/lib/spinner.test.js.map +1 -0
- package/dist/lib/style.d.ts +65 -0
- package/dist/lib/style.d.ts.map +1 -0
- package/dist/lib/style.js +108 -0
- package/dist/lib/style.js.map +1 -0
- package/dist/lib/style.test.d.ts +7 -0
- package/dist/lib/style.test.d.ts.map +1 -0
- package/dist/lib/style.test.js +195 -0
- package/dist/lib/style.test.js.map +1 -0
- package/dist/lib/workspace-probe.d.ts +16 -0
- package/dist/lib/workspace-probe.d.ts.map +1 -0
- package/dist/lib/workspace-probe.js +33 -0
- package/dist/lib/workspace-probe.js.map +1 -0
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -7,10 +7,11 @@
|
|
|
7
7
|
import { readFileSync } from 'node:fs';
|
|
8
8
|
import { dirname, join } from 'node:path';
|
|
9
9
|
import { fileURLToPath } from 'node:url';
|
|
10
|
-
import { Command } from 'commander';
|
|
10
|
+
import { Command, CommanderError } from 'commander';
|
|
11
11
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
12
12
|
const cliPackageVersion = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf8'));
|
|
13
|
-
import { setOutputMode } from './lib/runner.js';
|
|
13
|
+
import { setOutputMode, setQuietMode, isJsonMode } from './lib/runner.js';
|
|
14
|
+
import { CLIError, ErrorCode } from './lib/errors.js';
|
|
14
15
|
import { runContext } from './commands/context.js';
|
|
15
16
|
import { runGet, runGetMany } from './commands/get.js';
|
|
16
17
|
import { runLogin } from './commands/login.js';
|
|
@@ -38,15 +39,73 @@ import { runBrief, runCompoundBrief, isCompoundType } from './commands/brief.js'
|
|
|
38
39
|
import { runVerify } from './commands/verify.js';
|
|
39
40
|
import { runCodexPrep } from './commands/codex-prep.js';
|
|
40
41
|
import { runCollectionsList, runCollectionsGet, runCollectionsAudit, runCollectionsExport } from './commands/collections.js';
|
|
42
|
+
import { runWorkspaceVerify, runWorkspaceRepair, runDefinitionsDiff } from './commands/workspace.js';
|
|
41
43
|
import { runDoctor } from './commands/doctor.js';
|
|
44
|
+
import { runProfileList, runProfileCreate, runProfileUse, runProfileDelete } from './commands/profile.js';
|
|
45
|
+
import { runInit } from './commands/init.js';
|
|
46
|
+
import { GLOSSARY, formatGlossary } from './lib/glossary.js';
|
|
47
|
+
import { hint, heading, bold, dim, green, icons } from './lib/style.js';
|
|
48
|
+
import { readSession } from './lib/session.js';
|
|
49
|
+
import { formatElapsed } from './lib/format.js';
|
|
50
|
+
import { probeWorkspace } from './lib/workspace-probe.js';
|
|
42
51
|
const program = new Command();
|
|
52
|
+
/**
|
|
53
|
+
* Global error handler — single exit point for all CLI errors.
|
|
54
|
+
* CLIError: format with code + category + guidance.
|
|
55
|
+
* CommanderError: re-throw for --help / --version (exitCode 0), format others.
|
|
56
|
+
* Regular Error: wrap as INTERNAL.
|
|
57
|
+
*/
|
|
58
|
+
function handleError(err) {
|
|
59
|
+
// Commander help/version exits with code 0 — let them through
|
|
60
|
+
if (err instanceof CommanderError && err.exitCode === 0) {
|
|
61
|
+
process.exit(0);
|
|
62
|
+
}
|
|
63
|
+
const json = isJsonMode();
|
|
64
|
+
if (err instanceof CLIError) {
|
|
65
|
+
if (json) {
|
|
66
|
+
process.stderr.write(JSON.stringify(err.toJSON()) + '\n');
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
process.stderr.write(err.message + '\n');
|
|
70
|
+
if (err.guidance) {
|
|
71
|
+
process.stderr.write(err.guidance + '\n');
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
76
|
+
// CommanderError (bad usage, missing args, etc.)
|
|
77
|
+
if (err instanceof CommanderError) {
|
|
78
|
+
const cliErr = new CLIError(err.message, {
|
|
79
|
+
code: ErrorCode.VALIDATION_FAILED,
|
|
80
|
+
category: 'validation',
|
|
81
|
+
});
|
|
82
|
+
if (json) {
|
|
83
|
+
process.stderr.write(JSON.stringify(cliErr.toJSON()) + '\n');
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
process.stderr.write(err.message + '\n');
|
|
87
|
+
}
|
|
88
|
+
process.exit(err.exitCode);
|
|
89
|
+
}
|
|
90
|
+
// Unknown / unstructured errors
|
|
91
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
92
|
+
if (json) {
|
|
93
|
+
process.stderr.write(JSON.stringify({ error: message, code: 'INTERNAL', category: 'internal' }) + '\n');
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
process.stderr.write(message + '\n');
|
|
97
|
+
}
|
|
98
|
+
process.exit(1);
|
|
99
|
+
}
|
|
43
100
|
program
|
|
44
101
|
.name('pb')
|
|
45
102
|
.description('Product Brain — Chain knowledge + write-back CLI')
|
|
46
103
|
.version(cliPackageVersion.version)
|
|
47
104
|
// Global output mode flags (DEC-299, BET-181)
|
|
48
105
|
.option('--json', 'Output machine-readable JSON (overrides TTY auto-detection)')
|
|
49
|
-
.option('--pretty', 'Force human-readable output even when piped')
|
|
106
|
+
.option('--pretty', 'Force human-readable output even when piped')
|
|
107
|
+
.option('-q, --quiet', 'Suppress non-essential output (banners, hints, progress)')
|
|
108
|
+
.exitOverride(); // Throw CommanderError instead of calling process.exit directly
|
|
50
109
|
// Apply global output mode BEFORE subcommand actions run
|
|
51
110
|
program.hook('preAction', (thisCommand) => {
|
|
52
111
|
const globalOpts = program.opts();
|
|
@@ -57,8 +116,94 @@ program.hook('preAction', (thisCommand) => {
|
|
|
57
116
|
setOutputMode('pretty');
|
|
58
117
|
}
|
|
59
118
|
// else: 'auto' (default) — TTY detection handles it
|
|
119
|
+
if (globalOpts.quiet) {
|
|
120
|
+
setQuietMode(true);
|
|
121
|
+
}
|
|
60
122
|
void thisCommand;
|
|
61
123
|
});
|
|
124
|
+
// Default action — status dashboard when `pb` is invoked with no command.
|
|
125
|
+
// `pb --help` still works because Commander intercepts --help before the action runs.
|
|
126
|
+
program.action(async () => {
|
|
127
|
+
// Check if we have a valid API key (sync, no network)
|
|
128
|
+
let hasKey = false;
|
|
129
|
+
let config = null;
|
|
130
|
+
try {
|
|
131
|
+
const { getConfig: gc } = await import('./lib/config.js');
|
|
132
|
+
config = gc();
|
|
133
|
+
hasKey = true;
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
// No valid key
|
|
137
|
+
}
|
|
138
|
+
// JSON mode: structured status
|
|
139
|
+
if (isJsonMode()) {
|
|
140
|
+
if (!hasKey) {
|
|
141
|
+
process.stdout.write(JSON.stringify({
|
|
142
|
+
configured: false,
|
|
143
|
+
hint: 'Run pb login to configure your API key.',
|
|
144
|
+
}) + '\n');
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
const session = readSession();
|
|
148
|
+
const wsInfo = await probeWorkspace();
|
|
149
|
+
process.stdout.write(JSON.stringify({
|
|
150
|
+
configured: true,
|
|
151
|
+
workspace: wsInfo?.name ?? null,
|
|
152
|
+
session: session ? { id: session.sessionId, startedAt: session.startedAt } : null,
|
|
153
|
+
entryCount: wsInfo?.entryCount ?? null,
|
|
154
|
+
hint: 'Run pb --help for available commands.',
|
|
155
|
+
}) + '\n');
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
// Human mode — not configured
|
|
159
|
+
if (!hasKey) {
|
|
160
|
+
process.stdout.write('\n');
|
|
161
|
+
process.stdout.write(`${bold('Product Brain')} ${dim('— not connected')}\n\n`);
|
|
162
|
+
process.stdout.write(`${heading('Get started')}\n\n`);
|
|
163
|
+
hint('1. pb login Save your API key');
|
|
164
|
+
hint('2. pb setup Connect a workspace');
|
|
165
|
+
hint('3. pb orient -b See what\'s happening');
|
|
166
|
+
process.stdout.write('\n');
|
|
167
|
+
hint('pb --help Show all commands');
|
|
168
|
+
process.stdout.write('\n');
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
// Human mode — configured, try workspace probe
|
|
172
|
+
const session = readSession();
|
|
173
|
+
const wsInfo = await probeWorkspace();
|
|
174
|
+
const workspaceName = wsInfo?.name ?? null;
|
|
175
|
+
const entryCount = wsInfo?.entryCount ?? null;
|
|
176
|
+
const offline = !wsInfo;
|
|
177
|
+
process.stdout.write('\n');
|
|
178
|
+
if (offline) {
|
|
179
|
+
process.stdout.write(`${bold('Product Brain')} ${dim('— connected (offline)')}\n\n`);
|
|
180
|
+
process.stdout.write(` ${green(icons.pass)} Key: configured\n`);
|
|
181
|
+
process.stdout.write(` ${dim('Server: unreachable — check your connection')}\n\n`);
|
|
182
|
+
hint('pb doctor Diagnose connection issues');
|
|
183
|
+
hint('pb --help Show all commands');
|
|
184
|
+
process.stdout.write('\n');
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
// Online with workspace
|
|
188
|
+
const title = workspaceName
|
|
189
|
+
? `${bold('Product Brain')} ${dim('—')} ${bold(workspaceName)}`
|
|
190
|
+
: `${bold('Product Brain')}`;
|
|
191
|
+
process.stdout.write(`${title}\n\n`);
|
|
192
|
+
if (session) {
|
|
193
|
+
const elapsed = formatElapsed(session.startedAt);
|
|
194
|
+
process.stdout.write(` Session: active (started ${elapsed})\n`);
|
|
195
|
+
}
|
|
196
|
+
if (entryCount !== null && entryCount > 0) {
|
|
197
|
+
process.stdout.write(` Entries: ${entryCount}\n`);
|
|
198
|
+
}
|
|
199
|
+
process.stdout.write('\n');
|
|
200
|
+
if (!session) {
|
|
201
|
+
hint('pb session start Start a write session');
|
|
202
|
+
}
|
|
203
|
+
hint('pb orient -b Workspace overview');
|
|
204
|
+
hint('pb --help Show all commands');
|
|
205
|
+
process.stdout.write('\n');
|
|
206
|
+
});
|
|
62
207
|
program
|
|
63
208
|
.command('get <entry-id>')
|
|
64
209
|
.description('Display full entry by ID (data, relations, last 10 history events)')
|
|
@@ -67,25 +212,13 @@ program
|
|
|
67
212
|
program.commands.find((c) => c.name() === 'get')?.help();
|
|
68
213
|
return;
|
|
69
214
|
}
|
|
70
|
-
|
|
71
|
-
await runGet({ entryId: entryId.trim() });
|
|
72
|
-
}
|
|
73
|
-
catch (err) {
|
|
74
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
75
|
-
process.exit(1);
|
|
76
|
-
}
|
|
215
|
+
await runGet({ entryId: entryId.trim() });
|
|
77
216
|
});
|
|
78
217
|
program
|
|
79
218
|
.command('get-many <entry-ids...>')
|
|
80
219
|
.description('Fetch multiple entries in parallel (space-separated IDs)')
|
|
81
220
|
.action(async (entryIds) => {
|
|
82
|
-
|
|
83
|
-
await runGetMany({ entryIds: entryIds.map((id) => id.trim()).filter(Boolean) });
|
|
84
|
-
}
|
|
85
|
-
catch (err) {
|
|
86
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
87
|
-
process.exit(1);
|
|
88
|
-
}
|
|
221
|
+
await runGetMany({ entryIds: entryIds.map((id) => id.trim()).filter(Boolean) });
|
|
89
222
|
});
|
|
90
223
|
program
|
|
91
224
|
.command('context <entry-id>')
|
|
@@ -95,26 +228,14 @@ program
|
|
|
95
228
|
program.commands.find((c) => c.name() === 'context')?.help();
|
|
96
229
|
return;
|
|
97
230
|
}
|
|
98
|
-
|
|
99
|
-
await runContext({ entryId: entryId.trim() });
|
|
100
|
-
}
|
|
101
|
-
catch (err) {
|
|
102
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
103
|
-
process.exit(1);
|
|
104
|
-
}
|
|
231
|
+
await runContext({ entryId: entryId.trim() });
|
|
105
232
|
});
|
|
106
233
|
program
|
|
107
234
|
.command('changes')
|
|
108
235
|
.description('Detect entries modified and relations created since a given time (BET-239)')
|
|
109
236
|
.requiredOption('--since <duration>', 'Time window: 1h, 6h, 1d, 7d, 30d')
|
|
110
237
|
.action(async (opts) => {
|
|
111
|
-
|
|
112
|
-
await runChanges({ since: opts.since });
|
|
113
|
-
}
|
|
114
|
-
catch (err) {
|
|
115
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
116
|
-
process.exit(1);
|
|
117
|
-
}
|
|
238
|
+
await runChanges({ since: opts.since });
|
|
118
239
|
});
|
|
119
240
|
program
|
|
120
241
|
.command('walk <entry-id>')
|
|
@@ -123,36 +244,26 @@ program
|
|
|
123
244
|
.option('--direction <dir>', 'Traversal direction: outgoing or incoming (default outgoing)', 'outgoing')
|
|
124
245
|
.option('-t, --type <relation-type>', 'Filter by relation type (e.g. depends_on, informs, governs)')
|
|
125
246
|
.action(async (entryId, opts) => {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
132
|
-
await runChainWalk({
|
|
133
|
-
entryId: entryId.trim(),
|
|
134
|
-
depth,
|
|
135
|
-
direction: opts.direction,
|
|
136
|
-
type: opts.type,
|
|
247
|
+
const depth = parseInt(opts.depth, 10);
|
|
248
|
+
if (isNaN(depth) || depth < 1 || depth > 4) {
|
|
249
|
+
throw new CLIError('--depth must be between 1 and 4.', {
|
|
250
|
+
code: ErrorCode.VALIDATION_FAILED,
|
|
251
|
+
category: 'validation',
|
|
137
252
|
});
|
|
138
253
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
254
|
+
await runChainWalk({
|
|
255
|
+
entryId: entryId.trim(),
|
|
256
|
+
depth,
|
|
257
|
+
direction: opts.direction,
|
|
258
|
+
type: opts.type,
|
|
259
|
+
});
|
|
143
260
|
});
|
|
144
261
|
program
|
|
145
262
|
.command('cross-cut')
|
|
146
263
|
.description('Structural aggregation — all relations of a given type grouped by source collection (BET-239)')
|
|
147
264
|
.requiredOption('--type <relation-type>', 'Relation type to scan (e.g. part_of, informs, governs)')
|
|
148
265
|
.action(async (opts) => {
|
|
149
|
-
|
|
150
|
-
await runCrossCut({ type: opts.type });
|
|
151
|
-
}
|
|
152
|
-
catch (err) {
|
|
153
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
154
|
-
process.exit(1);
|
|
155
|
-
}
|
|
266
|
+
await runCrossCut({ type: opts.type });
|
|
156
267
|
});
|
|
157
268
|
program
|
|
158
269
|
.command('brief [type]')
|
|
@@ -165,27 +276,20 @@ program
|
|
|
165
276
|
.option('--since-last', 'Compare against last brief run (incremental mode)')
|
|
166
277
|
.option('--since <timestamp>', 'ISO 8601 timestamp for delta type (e.g. 2026-03-24T00:00:00Z)')
|
|
167
278
|
.action(async (type, opts) => {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
// Otherwise, require --skill for incremental brief
|
|
175
|
-
if (!opts.skill) {
|
|
176
|
-
console.error('Usage:\n' +
|
|
177
|
-
' pb brief --skill <name> Incremental delta\n' +
|
|
178
|
-
' pb brief steering Compound steering brief\n' +
|
|
179
|
-
' pb brief confidence Compound confidence pass\n' +
|
|
180
|
-
' pb brief delta Compound delta sync');
|
|
181
|
-
process.exit(1);
|
|
182
|
-
}
|
|
183
|
-
await runBrief({ skill: opts.skill, sinceLast: opts.sinceLast });
|
|
279
|
+
// If positional arg is a compound type, route to compound brief
|
|
280
|
+
if (type && isCompoundType(type)) {
|
|
281
|
+
await runCompoundBrief({ type, since: opts.since });
|
|
282
|
+
return;
|
|
184
283
|
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
284
|
+
// Otherwise, require --skill for incremental brief
|
|
285
|
+
if (!opts.skill) {
|
|
286
|
+
throw new CLIError('Usage:\n' +
|
|
287
|
+
' pb brief --skill <name> Incremental delta\n' +
|
|
288
|
+
' pb brief steering Compound steering brief\n' +
|
|
289
|
+
' pb brief confidence Compound confidence pass\n' +
|
|
290
|
+
' pb brief delta Compound delta sync', { code: ErrorCode.VALIDATION_FAILED, category: 'validation' });
|
|
188
291
|
}
|
|
292
|
+
await runBrief({ skill: opts.skill, sinceLast: opts.sinceLast });
|
|
189
293
|
});
|
|
190
294
|
program
|
|
191
295
|
.command('search [query...]')
|
|
@@ -196,13 +300,7 @@ program
|
|
|
196
300
|
program.commands.find((c) => c.name() === 'search')?.help();
|
|
197
301
|
return;
|
|
198
302
|
}
|
|
199
|
-
|
|
200
|
-
await runSearch({ query });
|
|
201
|
-
}
|
|
202
|
-
catch (err) {
|
|
203
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
204
|
-
process.exit(1);
|
|
205
|
-
}
|
|
303
|
+
await runSearch({ query });
|
|
206
304
|
});
|
|
207
305
|
program
|
|
208
306
|
.command('orient')
|
|
@@ -212,13 +310,7 @@ program
|
|
|
212
310
|
// SYNC: domain list must match TaskDomain in convex/mcpKnowledge/startupResolver.ts
|
|
213
311
|
.option('-s, --scope <domain>', 'Domain scope for governance filtering. Valid values: auth, governance, architecture, product, data-foundation, chainwork, capture-pipeline, ingestion, intelligence-and-operations, review-and-learning, general')
|
|
214
312
|
.action(async (opts) => {
|
|
215
|
-
|
|
216
|
-
await runOrient({ brief: opts.brief, task: opts.task?.trim() || undefined, scope: opts.scope?.trim() || undefined });
|
|
217
|
-
}
|
|
218
|
-
catch (err) {
|
|
219
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
220
|
-
process.exit(1);
|
|
221
|
-
}
|
|
313
|
+
await runOrient({ brief: opts.brief, task: opts.task?.trim() || undefined, scope: opts.scope?.trim() || undefined });
|
|
222
314
|
});
|
|
223
315
|
program
|
|
224
316
|
.command('handshake')
|
|
@@ -229,17 +321,11 @@ program
|
|
|
229
321
|
.option('--level <level>', 'With --init: trust level (guide|work|silent|full-trust). Without --init: content tier (beginner|intermediate|expert)')
|
|
230
322
|
.option('--generate', 'Fetch governance entries from the Chain and merge generated rules (BET-286)')
|
|
231
323
|
.action(async (opts) => {
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
return;
|
|
236
|
-
}
|
|
237
|
-
await runHandshake({ force: opts.force, dryRun: opts.dryRun, level: opts.level, generate: opts.generate });
|
|
238
|
-
}
|
|
239
|
-
catch (err) {
|
|
240
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
241
|
-
process.exit(1);
|
|
324
|
+
if (opts.init) {
|
|
325
|
+
await runHandshakeInit({ level: opts.level, dryRun: opts.dryRun });
|
|
326
|
+
return;
|
|
242
327
|
}
|
|
328
|
+
await runHandshake({ force: opts.force, dryRun: opts.dryRun, level: opts.level, generate: opts.generate });
|
|
243
329
|
});
|
|
244
330
|
program
|
|
245
331
|
.command('codex-prep <task...>')
|
|
@@ -251,49 +337,33 @@ program
|
|
|
251
337
|
program.commands.find((c) => c.name() === 'codex-prep')?.help();
|
|
252
338
|
return;
|
|
253
339
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
340
|
+
await runCodexPrep({ task, dryRun: opts.dryRun });
|
|
341
|
+
});
|
|
342
|
+
program
|
|
343
|
+
.command('init')
|
|
344
|
+
.description('Detect setup state and guide you through configuration (WP-303)')
|
|
345
|
+
.action(async () => {
|
|
346
|
+
await runInit();
|
|
261
347
|
});
|
|
262
348
|
program
|
|
263
349
|
.command('login')
|
|
264
350
|
.description('Save your API key to ~/.config/productbrain/.env (works from any directory)')
|
|
265
351
|
.action(async () => {
|
|
266
|
-
|
|
267
|
-
await runLogin();
|
|
268
|
-
}
|
|
269
|
-
catch (err) {
|
|
270
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
271
|
-
process.exit(1);
|
|
272
|
-
}
|
|
352
|
+
await runLogin();
|
|
273
353
|
});
|
|
274
354
|
program
|
|
275
355
|
.command('doctor')
|
|
276
356
|
.description('Check CLI configuration and connectivity')
|
|
277
|
-
.
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
}
|
|
281
|
-
catch (err) {
|
|
282
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
283
|
-
process.exit(1);
|
|
284
|
-
}
|
|
357
|
+
.option('--fix', 'Auto-repair common configuration issues')
|
|
358
|
+
.option('--dry-run', 'Preview what --fix would do without changing anything')
|
|
359
|
+
.action(async (opts) => {
|
|
360
|
+
await runDoctor({ fix: opts.fix, dryRun: opts.dryRun });
|
|
285
361
|
});
|
|
286
362
|
program
|
|
287
363
|
.command('setup')
|
|
288
364
|
.description('Guided first-time setup: account, login, workspace, first capture')
|
|
289
365
|
.action(async () => {
|
|
290
|
-
|
|
291
|
-
await runSetup();
|
|
292
|
-
}
|
|
293
|
-
catch (err) {
|
|
294
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
295
|
-
process.exit(1);
|
|
296
|
-
}
|
|
366
|
+
await runSetup();
|
|
297
367
|
});
|
|
298
368
|
// --- Write commands (require active session) ---
|
|
299
369
|
const sessionCmd = program
|
|
@@ -304,38 +374,20 @@ sessionCmd
|
|
|
304
374
|
.description('Start a tracked write session (opens session, refreshes context)')
|
|
305
375
|
.option('--json', 'Output machine-readable JSON (deprecated: use global --json flag)')
|
|
306
376
|
.action(async (opts) => {
|
|
307
|
-
|
|
308
|
-
await runSessionStart({ json: opts.json });
|
|
309
|
-
}
|
|
310
|
-
catch (err) {
|
|
311
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
312
|
-
process.exit(1);
|
|
313
|
-
}
|
|
377
|
+
await runSessionStart({ json: opts.json });
|
|
314
378
|
});
|
|
315
379
|
sessionCmd
|
|
316
380
|
.command('id')
|
|
317
381
|
.description('Print current session ID to stdout (machine-readable, TEN-707)')
|
|
318
382
|
.action(() => {
|
|
319
|
-
|
|
320
|
-
runSessionId();
|
|
321
|
-
}
|
|
322
|
-
catch (err) {
|
|
323
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
324
|
-
process.exit(1);
|
|
325
|
-
}
|
|
383
|
+
runSessionId();
|
|
326
384
|
});
|
|
327
385
|
sessionCmd
|
|
328
386
|
.command('close')
|
|
329
387
|
.description('Close the active session (wrapup, refresh context)')
|
|
330
388
|
.option('--force', 'Clear local session state even if server close fails')
|
|
331
389
|
.action(async (opts) => {
|
|
332
|
-
|
|
333
|
-
await runSessionClose({ force: opts.force });
|
|
334
|
-
}
|
|
335
|
-
catch (err) {
|
|
336
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
337
|
-
process.exit(1);
|
|
338
|
-
}
|
|
390
|
+
await runSessionClose({ force: opts.force });
|
|
339
391
|
});
|
|
340
392
|
program
|
|
341
393
|
.command('capture [text...]')
|
|
@@ -354,23 +406,17 @@ program
|
|
|
354
406
|
program.commands.find((c) => c.name() === 'capture')?.help();
|
|
355
407
|
return;
|
|
356
408
|
}
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
});
|
|
369
|
-
}
|
|
370
|
-
catch (err) {
|
|
371
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
372
|
-
process.exit(1);
|
|
373
|
-
}
|
|
409
|
+
await runCapture({
|
|
410
|
+
text: text || opts.name || '',
|
|
411
|
+
name: opts.name,
|
|
412
|
+
description: opts.description,
|
|
413
|
+
collection: opts.collection,
|
|
414
|
+
link: opts.link,
|
|
415
|
+
type: opts.type,
|
|
416
|
+
sourceRef: opts.sourceRef,
|
|
417
|
+
sourceExcerpt: opts.sourceExcerpt,
|
|
418
|
+
json: opts.json,
|
|
419
|
+
});
|
|
374
420
|
});
|
|
375
421
|
// --- Update command (TEN-703) ---
|
|
376
422
|
program
|
|
@@ -382,20 +428,14 @@ program
|
|
|
382
428
|
.option('--workflow-status <status>', 'Set workflow status (server-validated)')
|
|
383
429
|
.option('--note <text>', 'Change note for history')
|
|
384
430
|
.action(async (entryId, opts) => {
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
});
|
|
394
|
-
}
|
|
395
|
-
catch (err) {
|
|
396
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
397
|
-
process.exit(1);
|
|
398
|
-
}
|
|
431
|
+
await runUpdate({
|
|
432
|
+
entryId,
|
|
433
|
+
field: opts.field,
|
|
434
|
+
name: opts.name,
|
|
435
|
+
status: opts.status,
|
|
436
|
+
workflowStatus: opts.workflowStatus,
|
|
437
|
+
note: opts.note,
|
|
438
|
+
});
|
|
399
439
|
});
|
|
400
440
|
// --- Promote command (Wave 2 CLI Polish) ---
|
|
401
441
|
program
|
|
@@ -406,26 +446,14 @@ program
|
|
|
406
446
|
program.commands.find((c) => c.name() === 'verify')?.help();
|
|
407
447
|
return;
|
|
408
448
|
}
|
|
409
|
-
|
|
410
|
-
await runVerify({ entryId: entryId.trim() });
|
|
411
|
-
}
|
|
412
|
-
catch (err) {
|
|
413
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
414
|
-
process.exit(1);
|
|
415
|
-
}
|
|
449
|
+
await runVerify({ entryId: entryId.trim() });
|
|
416
450
|
});
|
|
417
451
|
program
|
|
418
452
|
.command('promote <entry-id>')
|
|
419
453
|
.description('Promote entry from draft to active (commit to SSOT)')
|
|
420
454
|
.option('-m, --message <text>', 'Commit message')
|
|
421
455
|
.action(async (entryId, opts) => {
|
|
422
|
-
|
|
423
|
-
await runPromote({ entryId, message: opts.message });
|
|
424
|
-
}
|
|
425
|
-
catch (err) {
|
|
426
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
427
|
-
process.exit(1);
|
|
428
|
-
}
|
|
456
|
+
await runPromote({ entryId, message: opts.message });
|
|
429
457
|
});
|
|
430
458
|
// --- Relate / Unrelate commands (TEN-704) ---
|
|
431
459
|
program
|
|
@@ -433,25 +461,13 @@ program
|
|
|
433
461
|
.description('Add a typed relation between two entries (requires active session)')
|
|
434
462
|
.option('--if-missing', 'Only create relation if it does not already exist')
|
|
435
463
|
.action(async (fromId, type, toId, opts) => {
|
|
436
|
-
|
|
437
|
-
await runRelate({ fromId, type, toId, ifMissing: opts.ifMissing });
|
|
438
|
-
}
|
|
439
|
-
catch (err) {
|
|
440
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
441
|
-
process.exit(1);
|
|
442
|
-
}
|
|
464
|
+
await runRelate({ fromId, type, toId, ifMissing: opts.ifMissing });
|
|
443
465
|
});
|
|
444
466
|
program
|
|
445
467
|
.command('unrelate <from-id> <type> <to-id>')
|
|
446
468
|
.description('Remove a typed relation between two entries (requires active session)')
|
|
447
469
|
.action(async (fromId, type, toId) => {
|
|
448
|
-
|
|
449
|
-
await runUnrelate({ fromId, type, toId });
|
|
450
|
-
}
|
|
451
|
-
catch (err) {
|
|
452
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
453
|
-
process.exit(1);
|
|
454
|
-
}
|
|
470
|
+
await runUnrelate({ fromId, type, toId });
|
|
455
471
|
});
|
|
456
472
|
// --- Ingest command (BET-81) ---
|
|
457
473
|
program
|
|
@@ -461,23 +477,19 @@ program
|
|
|
461
477
|
.option('--resume', 'Skip files whose sourceRef is already committed in staging.')
|
|
462
478
|
.option('--concurrency <n>', 'Process up to N files in parallel (default 1, max 5).', '1')
|
|
463
479
|
.action(async (pattern, opts) => {
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
}
|
|
470
|
-
await runIngest({
|
|
471
|
-
pattern,
|
|
472
|
-
dryRun: opts.dryRun,
|
|
473
|
-
resume: opts.resume,
|
|
474
|
-
concurrency,
|
|
480
|
+
const concurrency = parseInt(opts.concurrency ?? '1', 10);
|
|
481
|
+
if (Number.isNaN(concurrency) || concurrency < 1) {
|
|
482
|
+
throw new CLIError('--concurrency must be a positive integer.', {
|
|
483
|
+
code: ErrorCode.VALIDATION_FAILED,
|
|
484
|
+
category: 'validation',
|
|
475
485
|
});
|
|
476
486
|
}
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
487
|
+
await runIngest({
|
|
488
|
+
pattern,
|
|
489
|
+
dryRun: opts.dryRun,
|
|
490
|
+
resume: opts.resume,
|
|
491
|
+
concurrency,
|
|
492
|
+
});
|
|
481
493
|
});
|
|
482
494
|
// --- Fields command (BET-181 Slice 2) ---
|
|
483
495
|
program
|
|
@@ -488,13 +500,7 @@ program
|
|
|
488
500
|
program.commands.find((c) => c.name() === 'fields')?.help();
|
|
489
501
|
return;
|
|
490
502
|
}
|
|
491
|
-
|
|
492
|
-
await runFields({ collectionSlug: collection.trim() });
|
|
493
|
-
}
|
|
494
|
-
catch (err) {
|
|
495
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
496
|
-
process.exit(1);
|
|
497
|
-
}
|
|
503
|
+
await runFields({ collectionSlug: collection.trim() });
|
|
498
504
|
});
|
|
499
505
|
// --- Constellation command (BET-181 Slice 3) ---
|
|
500
506
|
program
|
|
@@ -505,13 +511,7 @@ program
|
|
|
505
511
|
program.commands.find((c) => c.name() === 'constellation')?.help();
|
|
506
512
|
return;
|
|
507
513
|
}
|
|
508
|
-
|
|
509
|
-
await runConstellation({ entryId: entryId.trim() });
|
|
510
|
-
}
|
|
511
|
-
catch (err) {
|
|
512
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
513
|
-
process.exit(1);
|
|
514
|
-
}
|
|
514
|
+
await runConstellation({ entryId: entryId.trim() });
|
|
515
515
|
});
|
|
516
516
|
// --- Audit command (BET-182 Slice 2) ---
|
|
517
517
|
program
|
|
@@ -522,19 +522,13 @@ program
|
|
|
522
522
|
.option('--fix', 'Auto-execute exact fixes via pb update, rerun once')
|
|
523
523
|
.option('--verbose', 'Show all gates including PASS detail')
|
|
524
524
|
.action(async (entryIds, opts) => {
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
});
|
|
533
|
-
}
|
|
534
|
-
catch (err) {
|
|
535
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
536
|
-
process.exit(1);
|
|
537
|
-
}
|
|
525
|
+
await runAudit({
|
|
526
|
+
entryIds: entryIds.map((id) => id.trim()).filter(Boolean),
|
|
527
|
+
phase: opts.phase,
|
|
528
|
+
gate: opts.gate,
|
|
529
|
+
fix: opts.fix,
|
|
530
|
+
verbose: opts.verbose,
|
|
531
|
+
});
|
|
538
532
|
});
|
|
539
533
|
program
|
|
540
534
|
.command('brand-pack')
|
|
@@ -549,13 +543,7 @@ program
|
|
|
549
543
|
.command('proposals')
|
|
550
544
|
.description('List open consent proposals with expiry countdown (BET-221)')
|
|
551
545
|
.action(async () => {
|
|
552
|
-
|
|
553
|
-
await runProposals();
|
|
554
|
-
}
|
|
555
|
-
catch (err) {
|
|
556
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
557
|
-
process.exit(1);
|
|
558
|
-
}
|
|
546
|
+
await runProposals();
|
|
559
547
|
});
|
|
560
548
|
program
|
|
561
549
|
.command('accept [proposal-id]')
|
|
@@ -563,29 +551,19 @@ program
|
|
|
563
551
|
.option('-a, --auto', 'Auto-approve all open proposals (skip contradictions)')
|
|
564
552
|
.action(async (proposalId, opts) => {
|
|
565
553
|
if (!proposalId && !opts.auto) {
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
await runAccept({ proposalId, auto: opts.auto });
|
|
571
|
-
}
|
|
572
|
-
catch (err) {
|
|
573
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
574
|
-
process.exit(1);
|
|
554
|
+
throw new CLIError('Usage: pb accept <proposal-id> or pb accept --auto', {
|
|
555
|
+
code: ErrorCode.VALIDATION_FAILED,
|
|
556
|
+
category: 'validation',
|
|
557
|
+
});
|
|
575
558
|
}
|
|
559
|
+
await runAccept({ proposalId, auto: opts.auto });
|
|
576
560
|
});
|
|
577
561
|
program
|
|
578
562
|
.command('reject <proposal-id>')
|
|
579
563
|
.description('Reject a consent proposal with a required reason (BR-7)')
|
|
580
564
|
.requiredOption('-r, --reason <text>', 'Reason for rejection (required)')
|
|
581
565
|
.action(async (proposalId, opts) => {
|
|
582
|
-
|
|
583
|
-
await runReject({ proposalId, reason: opts.reason });
|
|
584
|
-
}
|
|
585
|
-
catch (err) {
|
|
586
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
587
|
-
process.exit(1);
|
|
588
|
-
}
|
|
566
|
+
await runReject({ proposalId, reason: opts.reason });
|
|
589
567
|
});
|
|
590
568
|
// --- Collections command (BET-280 Slice 1) ---
|
|
591
569
|
const collectionsCmd = program
|
|
@@ -595,13 +573,7 @@ collectionsCmd
|
|
|
595
573
|
.command('list')
|
|
596
574
|
.description('List all collections — slug, name, field count, icon')
|
|
597
575
|
.action(async () => {
|
|
598
|
-
|
|
599
|
-
await runCollectionsList();
|
|
600
|
-
}
|
|
601
|
-
catch (err) {
|
|
602
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
603
|
-
process.exit(1);
|
|
604
|
-
}
|
|
576
|
+
await runCollectionsList();
|
|
605
577
|
});
|
|
606
578
|
collectionsCmd
|
|
607
579
|
.command('get <slug>')
|
|
@@ -611,37 +583,94 @@ collectionsCmd
|
|
|
611
583
|
program.commands.find((c) => c.name() === 'collections')?.help();
|
|
612
584
|
return;
|
|
613
585
|
}
|
|
614
|
-
|
|
615
|
-
await runCollectionsGet({ slug: slug.trim() });
|
|
616
|
-
}
|
|
617
|
-
catch (err) {
|
|
618
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
619
|
-
process.exit(1);
|
|
620
|
-
}
|
|
586
|
+
await runCollectionsGet({ slug: slug.trim() });
|
|
621
587
|
});
|
|
622
588
|
collectionsCmd
|
|
623
589
|
.command('audit')
|
|
624
590
|
.description('Collection health report — classification, icon, displayHint coverage, schema gaps')
|
|
625
591
|
.action(async () => {
|
|
626
|
-
|
|
627
|
-
await runCollectionsAudit();
|
|
628
|
-
}
|
|
629
|
-
catch (err) {
|
|
630
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
631
|
-
process.exit(1);
|
|
632
|
-
}
|
|
592
|
+
await runCollectionsAudit();
|
|
633
593
|
});
|
|
634
594
|
collectionsCmd
|
|
635
595
|
.command('export')
|
|
636
596
|
.description('Export all system_collection_definitions with full classification metadata (admin only)')
|
|
637
597
|
.action(async () => {
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
598
|
+
await runCollectionsExport();
|
|
599
|
+
});
|
|
600
|
+
// --- Workspace operator commands (WP-305 Slice 4) ---
|
|
601
|
+
const workspaceCmd = program
|
|
602
|
+
.command('workspace')
|
|
603
|
+
.description('Operator commands for workspace health and repair (WP-305)');
|
|
604
|
+
workspaceCmd
|
|
605
|
+
.command('verify')
|
|
606
|
+
.description('Check workspace health — seeds, collections, glossary (admin only)')
|
|
607
|
+
.action(async () => {
|
|
608
|
+
await runWorkspaceVerify();
|
|
645
609
|
});
|
|
646
|
-
|
|
610
|
+
workspaceCmd
|
|
611
|
+
.command('repair')
|
|
612
|
+
.description('Backfill missing seeds for the active workspace (admin only)')
|
|
613
|
+
.action(async () => {
|
|
614
|
+
await runWorkspaceRepair();
|
|
615
|
+
});
|
|
616
|
+
// --- Definitions diff command (WP-305 Slice 4) ---
|
|
617
|
+
const definitionsCmd = program
|
|
618
|
+
.command('definitions')
|
|
619
|
+
.description('Inspect and compare workspace definitions (WP-305)');
|
|
620
|
+
definitionsCmd
|
|
621
|
+
.command('diff [file]')
|
|
622
|
+
.description('Compare local dev-system-collections.json against server definitions (admin only)')
|
|
623
|
+
.action(async (file) => {
|
|
624
|
+
await runDefinitionsDiff({ file });
|
|
625
|
+
});
|
|
626
|
+
// --- Profile commands (WP-302 Slice 2) ---
|
|
627
|
+
const profileCmd = program
|
|
628
|
+
.command('profile')
|
|
629
|
+
.description('Manage workspace profiles (WP-302: multi-workspace support)');
|
|
630
|
+
profileCmd
|
|
631
|
+
.command('list')
|
|
632
|
+
.description('List all profiles, mark active one')
|
|
633
|
+
.action(async () => {
|
|
634
|
+
await runProfileList();
|
|
635
|
+
});
|
|
636
|
+
profileCmd
|
|
637
|
+
.command('create <name>')
|
|
638
|
+
.description('Create a new profile with an API key')
|
|
639
|
+
.requiredOption('--api-key <key>', 'API key (pb_sk_...)')
|
|
640
|
+
.option('--url <url>', 'Convex site URL (defaults to production)')
|
|
641
|
+
.action(async (name, opts) => {
|
|
642
|
+
await runProfileCreate({ name, apiKey: opts.apiKey, url: opts.url });
|
|
643
|
+
});
|
|
644
|
+
profileCmd
|
|
645
|
+
.command('use <name>')
|
|
646
|
+
.description('Switch active profile (closes any active session)')
|
|
647
|
+
.action(async (name) => {
|
|
648
|
+
await runProfileUse({ name });
|
|
649
|
+
});
|
|
650
|
+
profileCmd
|
|
651
|
+
.command('delete <name>')
|
|
652
|
+
.description('Delete a profile (cannot delete active or last profile)')
|
|
653
|
+
.action(async (name) => {
|
|
654
|
+
await runProfileDelete({ name });
|
|
655
|
+
});
|
|
656
|
+
// --- Glossary command (WP-302 Slice 4) ---
|
|
657
|
+
program
|
|
658
|
+
.command('glossary')
|
|
659
|
+
.description('Show key Product Brain CLI terms and definitions')
|
|
660
|
+
.action(() => {
|
|
661
|
+
if (isJsonMode()) {
|
|
662
|
+
process.stdout.write(JSON.stringify(GLOSSARY) + '\n');
|
|
663
|
+
return;
|
|
664
|
+
}
|
|
665
|
+
const lines = [
|
|
666
|
+
'',
|
|
667
|
+
heading('Glossary'),
|
|
668
|
+
'',
|
|
669
|
+
formatGlossary(),
|
|
670
|
+
'',
|
|
671
|
+
];
|
|
672
|
+
process.stdout.write(lines.join('\n') + '\n');
|
|
673
|
+
});
|
|
674
|
+
// Parse with global error handler — all uncaught errors route through handleError
|
|
675
|
+
program.parseAsync().catch(handleError);
|
|
647
676
|
//# sourceMappingURL=index.js.map
|