@principles/pd-cli 1.115.0 → 1.116.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/diagnose.d.ts.map +1 -1
- package/dist/commands/diagnose.js +153 -132
- package/dist/commands/diagnose.js.map +1 -1
- package/dist/commands/runtime-features.d.ts.map +1 -1
- package/dist/commands/runtime-features.js +2 -7
- package/dist/commands/runtime-features.js.map +1 -1
- package/dist/commands/runtime-internalization-integrity-repair.d.ts.map +1 -1
- package/dist/commands/runtime-internalization-integrity-repair.js +15 -31
- package/dist/commands/runtime-internalization-integrity-repair.js.map +1 -1
- package/dist/commands/runtime-internalization-run-once.d.ts.map +1 -1
- package/dist/commands/runtime-internalization-run-once.js +246 -326
- package/dist/commands/runtime-internalization-run-once.js.map +1 -1
- package/dist/commands/runtime-recovery.d.ts.map +1 -1
- package/dist/commands/runtime-recovery.js +9 -8
- package/dist/commands/runtime-recovery.js.map +1 -1
- package/dist/services/__tests__/cli-output.test.d.ts +18 -0
- package/dist/services/__tests__/cli-output.test.d.ts.map +1 -0
- package/dist/services/__tests__/cli-output.test.js +103 -0
- package/dist/services/__tests__/cli-output.test.js.map +1 -0
- package/dist/services/__tests__/runtime-adapter-resolver.test.d.ts +18 -0
- package/dist/services/__tests__/runtime-adapter-resolver.test.d.ts.map +1 -0
- package/dist/services/__tests__/runtime-adapter-resolver.test.js +651 -0
- package/dist/services/__tests__/runtime-adapter-resolver.test.js.map +1 -0
- package/dist/services/cli-output.d.ts +61 -0
- package/dist/services/cli-output.d.ts.map +1 -0
- package/dist/services/cli-output.js +72 -0
- package/dist/services/cli-output.js.map +1 -0
- package/dist/services/runtime-adapter-resolver.d.ts +105 -0
- package/dist/services/runtime-adapter-resolver.d.ts.map +1 -0
- package/dist/services/runtime-adapter-resolver.js +188 -0
- package/dist/services/runtime-adapter-resolver.js.map +1 -0
- package/package.json +1 -1
- package/src/commands/diagnose.ts +146 -138
- package/src/commands/runtime-features.ts +2 -6
- package/src/commands/runtime-internalization-integrity-repair.ts +16 -28
- package/src/commands/runtime-internalization-run-once.ts +242 -353
- package/src/commands/runtime-recovery.ts +9 -7
- package/src/services/__tests__/cli-output.test.ts +130 -0
- package/src/services/__tests__/runtime-adapter-resolver.test.ts +772 -0
- package/src/services/cli-output.ts +95 -0
- package/src/services/runtime-adapter-resolver.ts +339 -0
- package/tests/commands/diagnose.test.ts +7 -3
- package/tests/commands/runtime-internalization-run-once.test.ts +11 -0
- package/tests/commands/runtime-recovery.test.ts +27 -4
package/src/commands/diagnose.ts
CHANGED
|
@@ -23,8 +23,6 @@ import {
|
|
|
23
23
|
DisabledDiagnosticianRunner,
|
|
24
24
|
type DiagnosticianRunnerLike,
|
|
25
25
|
TestDoubleRuntimeAdapter,
|
|
26
|
-
OpenClawCliRuntimeAdapter,
|
|
27
|
-
PiAiRuntimeAdapter,
|
|
28
26
|
PDRuntimeError,
|
|
29
27
|
isRuntimeConfigError,
|
|
30
28
|
CandidateIntakeService,
|
|
@@ -32,12 +30,12 @@ import {
|
|
|
32
30
|
status as diagnoseStatus,
|
|
33
31
|
PrincipleTreeLedgerAdapter,
|
|
34
32
|
} from '@principles/core/runtime-v2';
|
|
35
|
-
import type { PDRuntimeAdapter,
|
|
33
|
+
import type { PDRuntimeAdapter, OutputLanguage } from '@principles/core/runtime-v2';
|
|
36
34
|
import { resolveWorkspaceDir } from '../resolve-workspace.js';
|
|
37
35
|
import { readOutputLanguageFromWorkspace } from '../config-reader.js';
|
|
38
36
|
import { loadPdConfig, computeFlagsFromLoadResult } from '../services/pd-config-loader.js';
|
|
39
|
-
import { resolveRuntimeFromPdConfig } from '../services/resolve-runtime-from-pd-config.js';
|
|
40
37
|
import { isFeatureEnabled, SPLIT_PIPELINE_TOTAL_TIMEOUT_MS } from '@principles/core/runtime-v2';
|
|
38
|
+
import { resolveRuntimeAdapterFromConfig, ConfigResolutionError } from '../services/runtime-adapter-resolver.js';
|
|
41
39
|
import * as path from 'path';
|
|
42
40
|
|
|
43
41
|
function validateStalledThreshold(val: unknown): number | undefined {
|
|
@@ -153,6 +151,38 @@ export async function handleDiagnoseStatus(opts: DiagnoseStatusOptions): Promise
|
|
|
153
151
|
}
|
|
154
152
|
}
|
|
155
153
|
|
|
154
|
+
/**
|
|
155
|
+
* PRI-431 Step 1d: Build diagnostician-specific test-double payload.
|
|
156
|
+
* Extracted from inline resolution in handleDiagnoseRun to use with shared resolver.
|
|
157
|
+
*/
|
|
158
|
+
function buildDiagnosticianTestDouble(taskId: string): PDRuntimeAdapter {
|
|
159
|
+
return new TestDoubleRuntimeAdapter({
|
|
160
|
+
onPollRun: (_runId: string) => ({
|
|
161
|
+
runId: _runId,
|
|
162
|
+
status: 'succeeded',
|
|
163
|
+
startedAt: new Date().toISOString(),
|
|
164
|
+
endedAt: new Date().toISOString(),
|
|
165
|
+
}),
|
|
166
|
+
onFetchOutput: (_runId: string) => ({
|
|
167
|
+
runId: _runId,
|
|
168
|
+
payload: {
|
|
169
|
+
valid: true,
|
|
170
|
+
diagnosisId: `diag-cli-${Date.now()}`,
|
|
171
|
+
taskId,
|
|
172
|
+
summary: 'CLI test diagnosis — validate tool arguments before execution',
|
|
173
|
+
rootCause: 'Test root cause — missing argument validation',
|
|
174
|
+
violatedPrinciples: [],
|
|
175
|
+
evidence: [],
|
|
176
|
+
recommendations: [
|
|
177
|
+
{ kind: 'principle', description: 'Always validate tool arguments before execution to prevent silent failures' },
|
|
178
|
+
{ kind: 'rule', description: 'Use schema validation for external inputs' },
|
|
179
|
+
],
|
|
180
|
+
confidence: 0.9,
|
|
181
|
+
},
|
|
182
|
+
}),
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
|
|
156
186
|
/**
|
|
157
187
|
* pd diagnose run --task-id <taskId> [--workspace <path>] [--json]
|
|
158
188
|
*
|
|
@@ -165,6 +195,7 @@ export async function handleDiagnoseRun(opts: DiagnoseRunOptions): Promise<void>
|
|
|
165
195
|
if (opts.openclawLocal && opts.openclawGateway) {
|
|
166
196
|
console.error('error: --openclaw-local and --openclaw-gateway are mutually exclusive');
|
|
167
197
|
process.exit(1);
|
|
198
|
+
return;
|
|
168
199
|
}
|
|
169
200
|
|
|
170
201
|
const runtimeKind = opts.runtime ?? 'test-double';
|
|
@@ -184,153 +215,130 @@ export async function handleDiagnoseRun(opts: DiagnoseRunOptions): Promise<void>
|
|
|
184
215
|
const contextAssembler = new SqliteContextAssembler(taskStore, historyQuery, runStore, { sourceTraceLocator });
|
|
185
216
|
|
|
186
217
|
// Select runtime adapter based on --runtime flag (CLI-02)
|
|
187
|
-
|
|
218
|
+
// PRI-431: migrated to shared resolveRuntimeAdapterFromConfig
|
|
188
219
|
let runtimeAdapter: PDRuntimeAdapter;
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
if (
|
|
220
|
+
// Capture config info for telemetry (resolver consumes config internally)
|
|
221
|
+
let telemetryConfig: { provider?: string; model?: string; openclawMode?: string } = {};
|
|
222
|
+
try {
|
|
223
|
+
if (runtimeKind === 'test-double') {
|
|
224
|
+
runtimeAdapter = resolveRuntimeAdapterFromConfig({
|
|
225
|
+
runtimeKind,
|
|
226
|
+
workspaceDir,
|
|
227
|
+
allowTestDouble: true,
|
|
228
|
+
testDoublePayloadBuilder: () => buildDiagnosticianTestDouble(opts.taskId),
|
|
229
|
+
});
|
|
230
|
+
} else if (runtimeKind === 'openclaw-cli') {
|
|
231
|
+
const flagMode: 'local' | 'gateway' | undefined = opts.openclawLocal
|
|
232
|
+
? 'local'
|
|
233
|
+
: opts.openclawGateway
|
|
234
|
+
? 'gateway'
|
|
235
|
+
: undefined;
|
|
236
|
+
runtimeAdapter = resolveRuntimeAdapterFromConfig({
|
|
237
|
+
runtimeKind,
|
|
238
|
+
workspaceDir,
|
|
239
|
+
openclawMode: flagMode,
|
|
240
|
+
agentId: opts.agent ?? 'main',
|
|
241
|
+
onConfigResolved: (resolved) => {
|
|
242
|
+
if (!isRuntimeConfigError(resolved.result)) {
|
|
243
|
+
telemetryConfig.openclawMode = flagMode ?? resolved.result.openclawMode;
|
|
244
|
+
} else {
|
|
245
|
+
telemetryConfig.openclawMode = flagMode;
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
});
|
|
249
|
+
// TELE-01: runtime_adapter_selected — user explicitly chose openclaw-cli runtime
|
|
250
|
+
storeEmitter.emitTelemetry({
|
|
251
|
+
eventType: 'runtime_adapter_selected',
|
|
252
|
+
traceId: opts.taskId,
|
|
253
|
+
timestamp: new Date().toISOString(),
|
|
254
|
+
sessionId: 'pd-cli-diagnose',
|
|
255
|
+
agentId: 'openclaw-cli-adapter',
|
|
256
|
+
payload: {
|
|
257
|
+
runtimeKind: 'openclaw-cli',
|
|
258
|
+
runtimeMode: telemetryConfig.openclawMode ?? 'local',
|
|
259
|
+
},
|
|
260
|
+
});
|
|
261
|
+
} else if (runtimeKind === 'pi-ai') {
|
|
262
|
+
runtimeAdapter = resolveRuntimeAdapterFromConfig({
|
|
263
|
+
runtimeKind,
|
|
264
|
+
workspaceDir,
|
|
265
|
+
configOptional: true,
|
|
266
|
+
validateApiKeyEnv: true,
|
|
267
|
+
piAiOverrides: {
|
|
268
|
+
provider: opts.provider,
|
|
269
|
+
model: opts.model,
|
|
270
|
+
apiKeyEnv: opts.apiKeyEnv,
|
|
271
|
+
baseUrl: opts.baseUrl,
|
|
272
|
+
maxRetries: opts.maxRetries,
|
|
273
|
+
},
|
|
274
|
+
timeoutMs: opts.timeoutMs,
|
|
275
|
+
onConfigResolved: (resolved) => {
|
|
276
|
+
for (const w of resolved.legacyWarnings) console.warn(`[pd diagnose] ${w}`);
|
|
277
|
+
if (isRuntimeConfigError(resolved.result)) {
|
|
278
|
+
console.warn(`[pd diagnose] .pd/config.yaml resolution failed: ${resolved.result.message}. Using CLI flags if provided.`);
|
|
279
|
+
} else {
|
|
280
|
+
telemetryConfig.provider = resolved.result.provider;
|
|
281
|
+
telemetryConfig.model = resolved.result.model;
|
|
282
|
+
}
|
|
283
|
+
},
|
|
284
|
+
});
|
|
285
|
+
// TELE: runtime_adapter_selected telemetry
|
|
286
|
+
const telemetryProvider = opts.provider ?? telemetryConfig.provider;
|
|
287
|
+
const telemetryModel = opts.model ?? telemetryConfig.model;
|
|
288
|
+
storeEmitter.emitTelemetry({
|
|
289
|
+
eventType: 'runtime_adapter_selected',
|
|
290
|
+
traceId: opts.taskId,
|
|
291
|
+
timestamp: new Date().toISOString(),
|
|
292
|
+
sessionId: 'pd-cli-diagnose',
|
|
293
|
+
agentId: 'pi-ai-adapter',
|
|
294
|
+
payload: { runtimeKind: 'pi-ai', provider: telemetryProvider, model: telemetryModel, baseUrlPresent: !!opts.baseUrl },
|
|
295
|
+
});
|
|
296
|
+
} else {
|
|
297
|
+
const unsupportedResult = {
|
|
298
|
+
ok: false,
|
|
299
|
+
reason: `unsupported_runtime_kind: ${runtimeKind}`,
|
|
300
|
+
nextAction: 'Use one of: openclaw-cli, test-double, pi-ai',
|
|
301
|
+
};
|
|
193
302
|
if (opts.json) {
|
|
194
|
-
console.log(JSON.stringify(
|
|
303
|
+
console.log(JSON.stringify(unsupportedResult, null, 2));
|
|
195
304
|
} else {
|
|
196
|
-
console.error(`error: ${
|
|
197
|
-
console.error(`
|
|
305
|
+
console.error(`error: unknown runtime kind '${runtimeKind}' (supported: openclaw-cli, test-double, pi-ai)`);
|
|
306
|
+
console.error(`Next action: ${unsupportedResult.nextAction}`);
|
|
198
307
|
}
|
|
199
308
|
process.exit(1);
|
|
200
309
|
return;
|
|
201
310
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
311
|
+
} catch (err) {
|
|
312
|
+
if (err instanceof ConfigResolutionError) {
|
|
313
|
+
// Preserve original error format for openclaw-cli missing mode (backward compat)
|
|
314
|
+
if (err.kind === 'missing-fields' && err.missing?.includes('openclawMode')) {
|
|
315
|
+
if (opts.json) {
|
|
316
|
+
console.log(JSON.stringify({
|
|
317
|
+
ok: false,
|
|
318
|
+
reason: 'missing_openclaw_mode',
|
|
319
|
+
message: 'runtimeKind is openclaw-cli but no mode resolved',
|
|
320
|
+
nextAction: 'Provide --openclaw-local or --openclaw-gateway, or set openclawMode in .pd/config.yaml',
|
|
321
|
+
}));
|
|
322
|
+
} else {
|
|
323
|
+
console.error('error: runtimeKind is openclaw-cli but no mode resolved');
|
|
324
|
+
console.error('nextAction: Provide --openclaw-local or --openclaw-gateway, or set openclawMode in .pd/config.yaml');
|
|
325
|
+
}
|
|
326
|
+
process.exit(1);
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
// Default error formatting for other config resolution errors
|
|
207
330
|
if (opts.json) {
|
|
208
|
-
console.log(JSON.stringify({ ok: false, reason:
|
|
331
|
+
console.log(JSON.stringify({ ok: false, reason: err.kind, message: err.message, missing: err.missing, nextAction: err.nextAction ?? 'Check .pd/config.yaml and retry' }));
|
|
209
332
|
} else {
|
|
210
|
-
console.error(
|
|
211
|
-
|
|
333
|
+
console.error(`error: ${err.message}`);
|
|
334
|
+
if (err.nextAction) {
|
|
335
|
+
console.error(`nextAction: ${err.nextAction}`);
|
|
336
|
+
}
|
|
212
337
|
}
|
|
213
338
|
process.exit(1);
|
|
214
339
|
return;
|
|
215
340
|
}
|
|
216
|
-
|
|
217
|
-
runtimeAdapter = new OpenClawCliRuntimeAdapter({
|
|
218
|
-
runtimeMode: effectiveMode,
|
|
219
|
-
workspaceDir,
|
|
220
|
-
agentId: opts.agent ?? 'main',
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
// TELE-01: runtime_adapter_selected — user explicitly chose openclaw-cli runtime
|
|
224
|
-
storeEmitter.emitTelemetry({
|
|
225
|
-
eventType: 'runtime_adapter_selected',
|
|
226
|
-
traceId: opts.taskId,
|
|
227
|
-
timestamp: new Date().toISOString(),
|
|
228
|
-
sessionId: 'pd-cli-diagnose',
|
|
229
|
-
agentId: 'openclaw-cli-adapter',
|
|
230
|
-
payload: {
|
|
231
|
-
runtimeKind: 'openclaw-cli',
|
|
232
|
-
runtimeMode: effectiveMode,
|
|
233
|
-
},
|
|
234
|
-
});
|
|
235
|
-
} else if (runtimeKind === 'test-double') {
|
|
236
|
-
runtimeAdapter = new TestDoubleRuntimeAdapter({
|
|
237
|
-
onPollRun: (_runId: string) => ({
|
|
238
|
-
runId: _runId,
|
|
239
|
-
status: 'succeeded',
|
|
240
|
-
startedAt: new Date().toISOString(),
|
|
241
|
-
endedAt: new Date().toISOString(),
|
|
242
|
-
}),
|
|
243
|
-
onFetchOutput: (_runId: string) => ({
|
|
244
|
-
runId: _runId,
|
|
245
|
-
payload: {
|
|
246
|
-
valid: true,
|
|
247
|
-
diagnosisId: `diag-cli-${Date.now()}`,
|
|
248
|
-
taskId: opts.taskId,
|
|
249
|
-
summary: 'CLI test diagnosis — validate tool arguments before execution',
|
|
250
|
-
rootCause: 'Test root cause — missing argument validation',
|
|
251
|
-
violatedPrinciples: [],
|
|
252
|
-
evidence: [],
|
|
253
|
-
recommendations: [
|
|
254
|
-
{ kind: 'principle', description: 'Always validate tool arguments before execution to prevent silent failures' },
|
|
255
|
-
{ kind: 'rule', description: 'Use schema validation for external inputs' },
|
|
256
|
-
],
|
|
257
|
-
confidence: 0.9,
|
|
258
|
-
},
|
|
259
|
-
}),
|
|
260
|
-
});
|
|
261
|
-
} else if (runtimeKind === 'pi-ai') {
|
|
262
|
-
const resolved = resolveRuntimeFromPdConfig(workspaceDir);
|
|
263
|
-
for (const w of resolved.legacyWarnings) console.warn(`[pd diagnose] ${w}`);
|
|
264
|
-
|
|
265
|
-
let policyConfig: RuntimeConfig | null = null;
|
|
266
|
-
if (!isRuntimeConfigError(resolved.result)) {
|
|
267
|
-
policyConfig = resolved.result;
|
|
268
|
-
} else {
|
|
269
|
-
console.warn(`[pd diagnose] .pd/config.yaml resolution failed: ${resolved.result.message}. Using CLI flags if provided.`);
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
const provider = opts.provider ?? policyConfig?.provider;
|
|
273
|
-
const model = opts.model ?? policyConfig?.model;
|
|
274
|
-
const apiKeyEnv = opts.apiKeyEnv ?? policyConfig?.apiKeyEnv;
|
|
275
|
-
const baseUrl = opts.baseUrl ?? policyConfig?.baseUrl;
|
|
276
|
-
const maxRetries = opts.maxRetries ?? policyConfig?.maxRetries;
|
|
277
|
-
const effectiveTimeoutMs = opts.timeoutMs ?? policyConfig?.timeoutMs;
|
|
278
|
-
|
|
279
|
-
// D-11: validate config — missing fields + fix suggestion
|
|
280
|
-
const missing: string[] = [];
|
|
281
|
-
if (!provider) missing.push('provider');
|
|
282
|
-
if (!model) missing.push('model');
|
|
283
|
-
if (!apiKeyEnv) missing.push('apiKeyEnv');
|
|
284
|
-
if (missing.length > 0) {
|
|
285
|
-
console.error(
|
|
286
|
-
`error: missing required pi-ai config: ${missing.join(', ')}.\n` +
|
|
287
|
-
`Pass via --flag or add to .pd/config.yaml runtime profile.\n` +
|
|
288
|
-
`Example:\n` +
|
|
289
|
-
` pd diagnose run --runtime pi-ai --provider openrouter --model anthropic/claude-sonnet-4 --apiKeyEnv OPENROUTER_API_KEY\n` +
|
|
290
|
-
` Or add to .pd/config.yaml:\n` +
|
|
291
|
-
` runtimeProfiles:\n` +
|
|
292
|
-
` - id: openrouter\n` +
|
|
293
|
-
` type: pi-ai\n` +
|
|
294
|
-
` provider: openrouter\n` +
|
|
295
|
-
` model: anthropic/claude-sonnet-4\n` +
|
|
296
|
-
` apiKeyEnv: OPENROUTER_API_KEY`,
|
|
297
|
-
);
|
|
298
|
-
process.exit(1);
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
// After validation: all fields are confirmed non-null
|
|
302
|
-
const validProvider: string = provider as string;
|
|
303
|
-
const validModel: string = model as string;
|
|
304
|
-
const validApiKeyEnv: string = apiKeyEnv as string;
|
|
305
|
-
|
|
306
|
-
// D-09: validate env var exists
|
|
307
|
-
if (!process.env[validApiKeyEnv]) {
|
|
308
|
-
console.error(`error: environment variable '${validApiKeyEnv}' is not set`);
|
|
309
|
-
process.exit(1);
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
runtimeAdapter = new PiAiRuntimeAdapter({
|
|
313
|
-
provider: validProvider,
|
|
314
|
-
model: validModel,
|
|
315
|
-
apiKeyEnv: validApiKeyEnv,
|
|
316
|
-
baseUrl,
|
|
317
|
-
maxRetries,
|
|
318
|
-
timeoutMs: effectiveTimeoutMs,
|
|
319
|
-
workspace: workspaceDir,
|
|
320
|
-
});
|
|
321
|
-
|
|
322
|
-
// TELE: runtime_adapter_selected telemetry
|
|
323
|
-
storeEmitter.emitTelemetry({
|
|
324
|
-
eventType: 'runtime_adapter_selected',
|
|
325
|
-
traceId: opts.taskId,
|
|
326
|
-
timestamp: new Date().toISOString(),
|
|
327
|
-
sessionId: 'pd-cli-diagnose',
|
|
328
|
-
agentId: 'pi-ai-adapter',
|
|
329
|
-
payload: { runtimeKind: 'pi-ai', provider: validProvider, model: validModel, baseUrlPresent: !!baseUrl },
|
|
330
|
-
});
|
|
331
|
-
} else {
|
|
332
|
-
console.error(`error: unknown runtime kind '${runtimeKind}' (supported: openclaw-cli, test-double, pi-ai)`);
|
|
333
|
-
process.exit(1);
|
|
341
|
+
throw err;
|
|
334
342
|
}
|
|
335
343
|
|
|
336
344
|
const eventEmitter = new StoreEventEmitter();
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
import * as path from 'path';
|
|
13
13
|
import { loadPdConfig, computeFlagsFromLoadResult } from '../services/pd-config-loader.js';
|
|
14
14
|
import { resolveWorkspaceDir } from '../resolve-workspace.js';
|
|
15
|
+
import { emitResult } from '../services/cli-output.js';
|
|
15
16
|
|
|
16
17
|
// ── Output types ─────────────────────────────────────────────────────────────
|
|
17
18
|
|
|
@@ -144,12 +145,7 @@ export async function handleRuntimeFeaturesStatus(opts: FeaturesOptions): Promis
|
|
|
144
145
|
|
|
145
146
|
const output = buildRuntimeFeaturesStatus(workspaceDir);
|
|
146
147
|
|
|
147
|
-
|
|
148
|
-
// JSON mode: single parseable object on stdout
|
|
149
|
-
console.log(JSON.stringify(output, null, 2));
|
|
150
|
-
} else {
|
|
151
|
-
console.log(formatTextOutput(output));
|
|
152
|
-
}
|
|
148
|
+
emitResult(output, { json: opts.json ?? false, formatText: formatTextOutput });
|
|
153
149
|
|
|
154
150
|
if (output.status === 'failed') {
|
|
155
151
|
process.exitCode = 1;
|
|
@@ -2,6 +2,7 @@ import * as path from 'path';
|
|
|
2
2
|
import { InternalizationIntegrityRemediation } from '@principles/core/runtime-v2';
|
|
3
3
|
import { resolveWorkspaceDir } from '../resolve-workspace.js';
|
|
4
4
|
import type { RemediationResult } from './remediation-output.js';
|
|
5
|
+
import { emitResult, emitFlagConflict, emitError } from '../services/cli-output.js';
|
|
5
6
|
|
|
6
7
|
interface InternalizationIntegrityRepairOptions {
|
|
7
8
|
workspace?: string;
|
|
@@ -43,16 +44,8 @@ function formatTextOutput(result: RemediationResult): string {
|
|
|
43
44
|
|
|
44
45
|
export async function handleRuntimeInternalizationIntegrityRepair(opts: InternalizationIntegrityRepairOptions): Promise<void> {
|
|
45
46
|
if (opts.dryRun && opts.confirm) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
ok: false,
|
|
49
|
-
reason: 'Error: --dry-run and --confirm are mutually exclusive',
|
|
50
|
-
nextAction: 'Specify only one of --dry-run or --confirm',
|
|
51
|
-
}, null, 2));
|
|
52
|
-
} else {
|
|
53
|
-
console.error('Error: --dry-run and --confirm are mutually exclusive. Specify one or the other.');
|
|
54
|
-
}
|
|
55
|
-
process.exit(1);
|
|
47
|
+
const exitCode = emitFlagConflict({ json: opts.json ?? false });
|
|
48
|
+
process.exit(exitCode);
|
|
56
49
|
return;
|
|
57
50
|
}
|
|
58
51
|
|
|
@@ -66,26 +59,21 @@ export async function handleRuntimeInternalizationIntegrityRepair(opts: Internal
|
|
|
66
59
|
const remediation = new InternalizationIntegrityRemediation({ workspaceDir });
|
|
67
60
|
const result = remediation.repair({ dryRun: isDryRun });
|
|
68
61
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
62
|
+
emitResult(result, {
|
|
63
|
+
json: opts.json ?? false,
|
|
64
|
+
formatText: formatTextOutput,
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
if (!isDryRun && result.repairedCount === 0 && result.actions.length > 0 && !opts.json) {
|
|
68
|
+
console.error('');
|
|
69
|
+
console.error('NOTE: No repairs were made. All issues were already resolved or skipped.');
|
|
77
70
|
}
|
|
78
71
|
} catch (err: unknown) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}, null, 2));
|
|
85
|
-
} else {
|
|
86
|
-
console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
87
|
-
}
|
|
88
|
-
process.exit(1);
|
|
72
|
+
const exitCode = emitError(err, {
|
|
73
|
+
json: opts.json ?? false,
|
|
74
|
+
nextAction: 'Check workspace path and DB connectivity',
|
|
75
|
+
});
|
|
76
|
+
process.exit(exitCode);
|
|
89
77
|
return;
|
|
90
78
|
}
|
|
91
79
|
}
|