@principles/pd-cli 1.73.1 → 1.74.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/config-doctor.d.ts +20 -0
- package/dist/commands/config-doctor.d.ts.map +1 -0
- package/dist/commands/config-doctor.js +144 -0
- package/dist/commands/config-doctor.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +48 -29
- package/dist/index.js.map +1 -1
- package/dist/services/config-doctor.d.ts +142 -0
- package/dist/services/config-doctor.d.ts.map +1 -0
- package/dist/services/config-doctor.js +603 -0
- package/dist/services/config-doctor.js.map +1 -0
- package/package.json +4 -2
- package/src/commands/config-doctor.ts +158 -0
- package/src/index.ts +52 -30
- package/src/services/config-doctor.ts +763 -0
- package/tests/commands/cli-command-tree.test.ts +1 -1
- package/tests/commands/config-doctor.test.ts +624 -0
- package/tests/pd-cli-smoke.test.ts +12 -0
- package/dist/commands/runtime-idle-trigger.d.ts +0 -12
- package/dist/commands/runtime-idle-trigger.d.ts.map +0 -1
- package/dist/commands/runtime-idle-trigger.js +0 -102
- package/dist/commands/runtime-idle-trigger.js.map +0 -1
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pd config doctor — Discover and explain PD / OpenClaw configuration state.
|
|
3
|
+
*
|
|
4
|
+
* PRI-299 MVP UX:
|
|
5
|
+
* - Reports workspace + OpenClaw config paths and existence
|
|
6
|
+
* - Lists effective feature flags and enabled MVP channels
|
|
7
|
+
* - Classifies provider/model/auth connectivity (healthy, auth_missing, rate_limit, etc.)
|
|
8
|
+
* - Emits `reason` + `nextActions` for failures
|
|
9
|
+
* - NEVER leaks tokens, env var values, or raw config bytes
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* pd config doctor [--workspace <path>] [--json]
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import * as path from 'path';
|
|
16
|
+
import { resolveWorkspaceDir } from '../resolve-workspace.js';
|
|
17
|
+
import { buildDoctorOutput, type DoctorOutput } from '../services/config-doctor.js';
|
|
18
|
+
|
|
19
|
+
interface DoctorOptions {
|
|
20
|
+
workspace?: string;
|
|
21
|
+
json?: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function formatTextOutput(output: DoctorOutput): string {
|
|
25
|
+
const lines: string[] = [];
|
|
26
|
+
const statusIcon = output.status === 'ok' ? '✓' : output.status === 'degraded' ? '⚠' : '✗';
|
|
27
|
+
|
|
28
|
+
lines.push('PD Config Doctor');
|
|
29
|
+
lines.push(`status: ${statusIcon} ${output.status.toUpperCase()}`);
|
|
30
|
+
lines.push(`workspace: ${output.workspaceDir}`);
|
|
31
|
+
lines.push('');
|
|
32
|
+
|
|
33
|
+
lines.push('PD config paths:');
|
|
34
|
+
for (const [k, v] of Object.entries(output.pdConfigPaths)) {
|
|
35
|
+
const exists = v.exists ? '[exists]' : '[missing]';
|
|
36
|
+
lines.push(` ${k.padEnd(16)} ${exists.padEnd(10)} ${v.path}`);
|
|
37
|
+
}
|
|
38
|
+
lines.push('');
|
|
39
|
+
|
|
40
|
+
lines.push('OpenClaw paths:');
|
|
41
|
+
for (const [k, v] of Object.entries(output.openclawConfigPaths)) {
|
|
42
|
+
const exists = v.exists ? '[exists]' : '[missing]';
|
|
43
|
+
lines.push(` ${k.padEnd(16)} ${exists.padEnd(10)} ${v.path}`);
|
|
44
|
+
}
|
|
45
|
+
lines.push('');
|
|
46
|
+
|
|
47
|
+
lines.push(`Feature flags: source=${output.featureFlags.source}`);
|
|
48
|
+
lines.push(` enabled MVP channels: ${output.featureFlags.enabledMvpChannels.length === 0 ? '(none)' : output.featureFlags.enabledMvpChannels.join(', ')}`);
|
|
49
|
+
if (output.featureFlags.disabledFlags.length > 0) {
|
|
50
|
+
lines.push(` disabled: ${output.featureFlags.disabledFlags.join(', ')}`);
|
|
51
|
+
}
|
|
52
|
+
if (output.featureFlags.warnings.length > 0) {
|
|
53
|
+
lines.push(` warnings: ${output.featureFlags.warnings.length}`);
|
|
54
|
+
}
|
|
55
|
+
lines.push('');
|
|
56
|
+
|
|
57
|
+
lines.push('Provider health:');
|
|
58
|
+
if (output.providerHealth.length === 0) {
|
|
59
|
+
lines.push(' (no providers discovered)');
|
|
60
|
+
} else {
|
|
61
|
+
for (const p of output.providerHealth) {
|
|
62
|
+
const cls = p.classification.toUpperCase();
|
|
63
|
+
const provider = p.provider ?? '(unset)';
|
|
64
|
+
const model = p.model ?? '(unset)';
|
|
65
|
+
const apiKeyEnv = p.apiKeyEnv ?? '(unset)';
|
|
66
|
+
const apiKeyState = p.apiKeyPresent ? 'present' : 'absent';
|
|
67
|
+
lines.push(` [${cls}] ${provider} / ${model}`);
|
|
68
|
+
lines.push(` apiKeyEnv: ${apiKeyEnv} (${apiKeyState})`);
|
|
69
|
+
lines.push(` source: ${p.source}`);
|
|
70
|
+
lines.push(` reason: ${p.reason}`);
|
|
71
|
+
lines.push(` nextAction: ${p.nextAction}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
lines.push('');
|
|
75
|
+
|
|
76
|
+
lines.push('Internal agents:');
|
|
77
|
+
if (output.internalAgents && output.internalAgents.correctionObserver) {
|
|
78
|
+
const co = output.internalAgents.correctionObserver;
|
|
79
|
+
const coStatus = co.status.toUpperCase();
|
|
80
|
+
const coProvider = co.provider ?? '(unset)';
|
|
81
|
+
const coModel = co.model ?? '(unset)';
|
|
82
|
+
const coApiKeyEnv = co.apiKeyEnv ?? '(unset)';
|
|
83
|
+
const coApiKeyState = co.apiKeyPresent ? 'present' : 'absent';
|
|
84
|
+
lines.push(` correctionObserver: [${coStatus}]`);
|
|
85
|
+
lines.push(` enabled: ${co.enabled}`);
|
|
86
|
+
lines.push(` flagSource: ${co.flagSource}`);
|
|
87
|
+
lines.push(` configSource:${co.configSource}`);
|
|
88
|
+
if (co.provider || co.model) {
|
|
89
|
+
lines.push(` provider: ${coProvider} / ${coModel}`);
|
|
90
|
+
}
|
|
91
|
+
lines.push(` apiKeyEnv: ${coApiKeyEnv} (${coApiKeyState})`);
|
|
92
|
+
lines.push(` reason: ${co.reason}`);
|
|
93
|
+
lines.push(` nextAction: ${co.nextAction}`);
|
|
94
|
+
} else {
|
|
95
|
+
lines.push(' (no internal agents diagnosed)');
|
|
96
|
+
}
|
|
97
|
+
lines.push('');
|
|
98
|
+
|
|
99
|
+
if (output.warnings.length > 0) {
|
|
100
|
+
lines.push('Warnings:');
|
|
101
|
+
for (const w of output.warnings) {
|
|
102
|
+
lines.push(` [!] ${w}`);
|
|
103
|
+
}
|
|
104
|
+
lines.push('');
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (output.reason) {
|
|
108
|
+
lines.push(`Reason: ${output.reason}`);
|
|
109
|
+
lines.push('');
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (output.nextActions.length > 0) {
|
|
113
|
+
lines.push('Next actions:');
|
|
114
|
+
for (const a of output.nextActions) {
|
|
115
|
+
lines.push(` → ${a}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return lines.join('\n');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export async function handleConfigDoctor(opts: DoctorOptions): Promise<void> {
|
|
123
|
+
let workspaceDir: string;
|
|
124
|
+
try {
|
|
125
|
+
workspaceDir = opts.workspace ? path.resolve(opts.workspace) : resolveWorkspaceDir();
|
|
126
|
+
} catch (err) {
|
|
127
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
128
|
+
const output = {
|
|
129
|
+
status: 'failed' as const,
|
|
130
|
+
reason: 'workspace_resolution_failed',
|
|
131
|
+
message,
|
|
132
|
+
nextActions: ['Pass --workspace <path> explicitly, or set PD_WORKSPACE_DIR environment variable'],
|
|
133
|
+
};
|
|
134
|
+
if (opts.json) {
|
|
135
|
+
console.log(JSON.stringify(output, null, 2));
|
|
136
|
+
} else {
|
|
137
|
+
console.error(`error: ${message}`);
|
|
138
|
+
}
|
|
139
|
+
process.exit(1);
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const output = await buildDoctorOutput({ workspaceDir });
|
|
144
|
+
|
|
145
|
+
if (opts.json) {
|
|
146
|
+
// JSON mode: single parseable object on stdout.
|
|
147
|
+
console.log(JSON.stringify(output, null, 2));
|
|
148
|
+
} else {
|
|
149
|
+
console.log(formatTextOutput(output));
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (output.status === 'failed') {
|
|
153
|
+
process.exitCode = 1;
|
|
154
|
+
} else if (output.status === 'degraded') {
|
|
155
|
+
// degraded: do not exit 1, but emit a hint to stderr for the operator.
|
|
156
|
+
console.error(`\nNote: doctor status is degraded. Inspect warnings + nextActions.`);
|
|
157
|
+
}
|
|
158
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* pd CLI
|
|
3
|
+
* pd CLI 鈥?Principles Disciple command-line interface.
|
|
4
4
|
*
|
|
5
5
|
* Usage:
|
|
6
6
|
* pd pain record --reason <text> [--score N] [--source manual]
|
|
@@ -47,12 +47,16 @@ import { handleProvenChannelBaseline } from './commands/proven-channel-baseline.
|
|
|
47
47
|
import { handleDemoStoryA } from './commands/demo-story-a.js';
|
|
48
48
|
import { handleRuntimeFeaturesStatus } from './commands/runtime-features.js';
|
|
49
49
|
|
|
50
|
+
import { createRequire } from 'module';
|
|
51
|
+
const require = createRequire(import.meta.url);
|
|
52
|
+
const pkg = require('../package.json') as { version: string };
|
|
53
|
+
|
|
50
54
|
const program = new Command();
|
|
51
55
|
|
|
52
56
|
program
|
|
53
57
|
.name('pd')
|
|
54
|
-
.description('PD CLI
|
|
55
|
-
.version(
|
|
58
|
+
.description('PD CLI 鈥?Pain recording, sample management, and evolution tasks')
|
|
59
|
+
.version(pkg.version);
|
|
56
60
|
|
|
57
61
|
const painCmd = program
|
|
58
62
|
.command('pain')
|
|
@@ -143,7 +147,7 @@ centralCmd
|
|
|
143
147
|
await handleCentralSync();
|
|
144
148
|
});
|
|
145
149
|
|
|
146
|
-
//
|
|
150
|
+
// 鈹€鈹€ Runtime v2 task/run commands 鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€
|
|
147
151
|
|
|
148
152
|
const rtTaskCmd = program
|
|
149
153
|
.command('task')
|
|
@@ -186,7 +190,7 @@ rtRunCmd
|
|
|
186
190
|
await handleRunShow({ id: runId });
|
|
187
191
|
});
|
|
188
192
|
|
|
189
|
-
//
|
|
193
|
+
// 鈹€鈹€ Runtime v2 trajectory/history/context commands 鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€
|
|
190
194
|
|
|
191
195
|
const trajectoryCmd = program
|
|
192
196
|
.command('trajectory')
|
|
@@ -235,7 +239,7 @@ contextCmd
|
|
|
235
239
|
await handleContextBuild(taskId, opts);
|
|
236
240
|
});
|
|
237
241
|
|
|
238
|
-
//
|
|
242
|
+
// 鈹€鈹€ Legacy import command 鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€
|
|
239
243
|
|
|
240
244
|
const legacyCmd = program
|
|
241
245
|
.command('legacy')
|
|
@@ -254,7 +258,7 @@ importCmd
|
|
|
254
258
|
await handleLegacyImportOpenClaw(opts);
|
|
255
259
|
});
|
|
256
260
|
|
|
257
|
-
//
|
|
261
|
+
// 鈹€鈹€ Diagnostician run/status commands 鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€
|
|
258
262
|
|
|
259
263
|
const diagnoseCmd = program
|
|
260
264
|
.command('diagnose')
|
|
@@ -279,19 +283,19 @@ diagnoseCmd
|
|
|
279
283
|
.option('--openclaw-local', 'Use local OpenClaw (mutually exclusive with --openclaw-gateway)')
|
|
280
284
|
.option('--openclaw-gateway', 'Use gateway OpenClaw (mutually exclusive with --openclaw-local)')
|
|
281
285
|
.option('-a, --agent <agentId>', 'Agent ID to invoke')
|
|
282
|
-
.option('--provider <name>', 'LLM provider (e.g., openrouter)
|
|
283
|
-
.option('--model <id>', 'Model ID (e.g., anthropic/claude-sonnet-4)
|
|
284
|
-
.option('--apiKeyEnv <name>', 'Env var name for API key
|
|
285
|
-
.option('--baseUrl <url>', 'Custom base URL
|
|
286
|
-
.option('--maxRetries <n>', 'Max retry attempts for LLM failures
|
|
287
|
-
.option('--timeoutMs <ms>', 'Timeout in milliseconds
|
|
286
|
+
.option('--provider <name>', 'LLM provider (e.g., openrouter) 鈥?for pi-ai, falls back to policy')
|
|
287
|
+
.option('--model <id>', 'Model ID (e.g., anthropic/claude-sonnet-4) 鈥?for pi-ai, falls back to policy')
|
|
288
|
+
.option('--apiKeyEnv <name>', 'Env var name for API key 鈥?for pi-ai, falls back to policy')
|
|
289
|
+
.option('--baseUrl <url>', 'Custom base URL 鈥?for pi-ai, falls back to policy')
|
|
290
|
+
.option('--maxRetries <n>', 'Max retry attempts for LLM failures 鈥?for pi-ai, falls back to policy', parseInt)
|
|
291
|
+
.option('--timeoutMs <ms>', 'Timeout in milliseconds 鈥?for pi-ai, falls back to policy', parseInt)
|
|
288
292
|
.option('--no-intake', 'Skip candidate intake after successful diagnosis')
|
|
289
293
|
.option('--json', 'Output raw JSON')
|
|
290
294
|
.action(async (opts) => {
|
|
291
295
|
await handleDiagnoseRun(opts);
|
|
292
296
|
});
|
|
293
297
|
|
|
294
|
-
//
|
|
298
|
+
// 鈹€鈹€ Runtime probe command (HG-01 HARD GATE) 鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€
|
|
295
299
|
|
|
296
300
|
const runtimeCmd = program
|
|
297
301
|
.command('runtime')
|
|
@@ -312,7 +316,7 @@ const synthCmd = runtimeCmd
|
|
|
312
316
|
|
|
313
317
|
synthCmd
|
|
314
318
|
.command('baseline')
|
|
315
|
-
.description('Run synthetic PD workload baseline (PRI-206)
|
|
319
|
+
.description('Run synthetic PD workload baseline (PRI-206) 鈥?deterministic, no LLM required')
|
|
316
320
|
.option('-w, --workspace <path>', 'Workspace directory (default: temp workspace)')
|
|
317
321
|
.option('--json', 'Output raw JSON')
|
|
318
322
|
.action(async (opts) => {
|
|
@@ -321,7 +325,7 @@ synthCmd
|
|
|
321
325
|
|
|
322
326
|
synthCmd
|
|
323
327
|
.command('flood')
|
|
324
|
-
.description('Run pain flood simulation (PRI-208)
|
|
328
|
+
.description('Run pain flood simulation (PRI-208) 鈥?deterministic dedup/stress test, no LLM required')
|
|
325
329
|
.option('-w, --workspace <path>', 'Workspace directory (default: temp workspace)')
|
|
326
330
|
.option('--json', 'Output raw JSON')
|
|
327
331
|
.option('--identical-count <n>', 'Number of identical pain signals (default: 10)', parseInt)
|
|
@@ -339,7 +343,7 @@ synthCmd
|
|
|
339
343
|
|
|
340
344
|
synthCmd
|
|
341
345
|
.command('proven-channel')
|
|
342
|
-
.description('Run MVP activation continuity baseline (PRI-240)
|
|
346
|
+
.description('Run MVP activation continuity baseline (PRI-240) 鈥?deterministic, no LLM required')
|
|
343
347
|
.option('-w, --workspace <path>', 'Workspace directory (default: temp workspace)')
|
|
344
348
|
.option('--json', 'Output raw JSON')
|
|
345
349
|
.option('--channels <channels>', 'Comma-separated channel list (prompt,code_tool_hook,defer_archive)')
|
|
@@ -369,7 +373,7 @@ const demoCmd = program
|
|
|
369
373
|
|
|
370
374
|
demoCmd
|
|
371
375
|
.command('story-a')
|
|
372
|
-
.description('Run Story A\' proven-channel demo (PRI-246)
|
|
376
|
+
.description('Run Story A\' proven-channel demo (PRI-246) 鈥?full evidence鈫抪roposal鈫抋pproval鈫抋ctivation鈫抩bservation chain')
|
|
373
377
|
.option('-w, --workspace <path>', 'Workspace directory (default: temp workspace)')
|
|
374
378
|
.option('--json', 'Output raw JSON')
|
|
375
379
|
.option('--channels <channels>', 'Comma-separated channel list (prompt,code_tool_hook,defer_archive)')
|
|
@@ -388,13 +392,13 @@ runtimeCmd
|
|
|
388
392
|
.option('--openclaw-local', 'Use local OpenClaw (mutually exclusive with --openclaw-gateway)')
|
|
389
393
|
.option('--openclaw-gateway', 'Use gateway OpenClaw (mutually exclusive with --openclaw-local)')
|
|
390
394
|
.option('-a, --agent <agentId>', 'Agent ID to probe')
|
|
391
|
-
.option('--provider <name>', 'LLM provider (e.g., openrouter)
|
|
392
|
-
.option('--model <id>', 'Model ID (e.g., anthropic/claude-sonnet-4)
|
|
393
|
-
.option('--apiKeyEnv <name>', 'Env var name for API key (e.g., OPENROUTER_API_KEY)
|
|
394
|
-
.option('--baseUrl <url>', 'Custom base URL for OpenAI-compatible providers
|
|
395
|
+
.option('--provider <name>', 'LLM provider (e.g., openrouter) 鈥?for pi-ai, falls back to --workspace workflows.yaml')
|
|
396
|
+
.option('--model <id>', 'Model ID (e.g., anthropic/claude-sonnet-4) 鈥?for pi-ai, falls back to --workspace workflows.yaml')
|
|
397
|
+
.option('--apiKeyEnv <name>', 'Env var name for API key (e.g., OPENROUTER_API_KEY) 鈥?for pi-ai, falls back to --workspace workflows.yaml')
|
|
398
|
+
.option('--baseUrl <url>', 'Custom base URL for OpenAI-compatible providers 鈥?for pi-ai, falls back to --workspace workflows.yaml')
|
|
395
399
|
.option('--maxRetries <n>', 'Max retry attempts for LLM failures', parseInt)
|
|
396
400
|
.option('--timeoutMs <ms>', 'Timeout in milliseconds for probe', parseInt)
|
|
397
|
-
.option('-w, --workspace <path>', 'Workspace directory
|
|
401
|
+
.option('-w, --workspace <path>', 'Workspace directory 鈥?loads pi-ai policy from .state/workflows.yaml')
|
|
398
402
|
.option('--json', 'Output raw JSON')
|
|
399
403
|
.action(async (opts) => {
|
|
400
404
|
await handleRuntimeProbe(opts);
|
|
@@ -458,17 +462,17 @@ runtimeHealthCmd
|
|
|
458
462
|
|
|
459
463
|
runtimeHealthCmd
|
|
460
464
|
.command('gfi')
|
|
461
|
-
.description('GFI workspace snapshot
|
|
465
|
+
.description('GFI workspace snapshot 鈥?active vs stale session breakdown')
|
|
462
466
|
.option('-w, --workspace <path>', 'Workspace directory')
|
|
463
467
|
.option('--json', 'Output raw JSON')
|
|
464
468
|
.action(async (opts) => {
|
|
465
469
|
await handleRuntimeGfiSnapshot({ workspace: opts.workspace, json: opts.json });
|
|
466
470
|
});
|
|
467
471
|
|
|
468
|
-
// PRI-82: pd runtime gfi snapshot
|
|
472
|
+
// PRI-82: pd runtime gfi snapshot 鈥?canonical operator command (alias of runtime health gfi)
|
|
469
473
|
runtimeCmd
|
|
470
474
|
.command('gfi')
|
|
471
|
-
.description('GFI workspace snapshot
|
|
475
|
+
.description('GFI workspace snapshot 鈥?active vs stale session breakdown')
|
|
472
476
|
.command('snapshot')
|
|
473
477
|
.description('GFI workspace snapshot for the operator (alias: pd runtime health gfi)')
|
|
474
478
|
.option('-w, --workspace <path>', 'Workspace directory')
|
|
@@ -604,7 +608,7 @@ const pruningCmd = runtimeCmd
|
|
|
604
608
|
|
|
605
609
|
pruningCmd
|
|
606
610
|
.command('report')
|
|
607
|
-
.description('Show pruning health report
|
|
611
|
+
.description('Show pruning health report 鈥?watch/review principle signals')
|
|
608
612
|
.option('-w, --workspace <path>', 'Workspace directory')
|
|
609
613
|
.option('--json', 'Output raw JSON')
|
|
610
614
|
.action((opts) => {
|
|
@@ -675,7 +679,7 @@ pruningCmd
|
|
|
675
679
|
});
|
|
676
680
|
});
|
|
677
681
|
|
|
678
|
-
//
|
|
682
|
+
// 鈹€鈹€ Candidate inspection commands 鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€
|
|
679
683
|
|
|
680
684
|
const candidateCmd = program
|
|
681
685
|
.command('candidate')
|
|
@@ -779,7 +783,7 @@ candidateInternalizationCmd
|
|
|
779
783
|
await handleCandidateInternalizationBackfill({ workspace: opts.workspace, dryRun: opts.dryRun, confirm: opts.confirm, includePending: opts.includePending, json: opts.json });
|
|
780
784
|
});
|
|
781
785
|
|
|
782
|
-
//
|
|
786
|
+
// 鈹€鈹€ Artifact inspection commands 鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€
|
|
783
787
|
|
|
784
788
|
const artifactCmd = program
|
|
785
789
|
.command('artifact')
|
|
@@ -826,4 +830,22 @@ program
|
|
|
826
830
|
});
|
|
827
831
|
});
|
|
828
832
|
|
|
833
|
+
// PRI-299: PD Config Doctor 鈥?surface config paths, feature flags, and provider connectivity
|
|
834
|
+
const configCmd = program
|
|
835
|
+
.command('config')
|
|
836
|
+
.description('PD config diagnostics');
|
|
837
|
+
|
|
838
|
+
configCmd
|
|
839
|
+
.command('doctor')
|
|
840
|
+
.description('Inspect PD / OpenClaw config paths, feature flags, and provider connectivity (PRI-299)')
|
|
841
|
+
.option('-w, --workspace <path>', 'Workspace directory')
|
|
842
|
+
.option('--json', 'Output a single parseable JSON object on stdout', false)
|
|
843
|
+
.action(async (opts) => {
|
|
844
|
+
const { handleConfigDoctor } = await import('./commands/config-doctor.js');
|
|
845
|
+
await handleConfigDoctor({
|
|
846
|
+
workspace: opts.workspace,
|
|
847
|
+
json: opts.json,
|
|
848
|
+
});
|
|
849
|
+
});
|
|
850
|
+
|
|
829
851
|
program.parse();
|