@principles/pd-cli 1.152.11 → 1.152.13
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/candidate.d.ts +3 -3
- package/dist/commands/candidate.d.ts.map +1 -1
- package/dist/commands/candidate.js +9 -21
- package/dist/commands/candidate.js.map +1 -1
- package/dist/index.js +0 -0
- package/dist/services/rulehost-pipeline-runner.d.ts.map +1 -1
- package/dist/services/rulehost-pipeline-runner.js +4 -17
- package/dist/services/rulehost-pipeline-runner.js.map +1 -1
- package/package.json +13 -7
- package/dist/commands/__tests__/intent-flag-wiring.test.d.ts +0 -9
- package/dist/commands/__tests__/intent-flag-wiring.test.d.ts.map +0 -1
- package/dist/commands/__tests__/intent-flag-wiring.test.js +0 -237
- package/dist/commands/__tests__/intent-flag-wiring.test.js.map +0 -1
- package/dist/commands/__tests__/legacy-cleanup.test.d.ts +0 -18
- package/dist/commands/__tests__/legacy-cleanup.test.d.ts.map +0 -1
- package/dist/commands/__tests__/legacy-cleanup.test.js +0 -467
- package/dist/commands/__tests__/legacy-cleanup.test.js.map +0 -1
- package/dist/commands/__tests__/mvp-smoke.test.d.ts +0 -15
- package/dist/commands/__tests__/mvp-smoke.test.d.ts.map +0 -1
- package/dist/commands/__tests__/mvp-smoke.test.js +0 -262
- package/dist/commands/__tests__/mvp-smoke.test.js.map +0 -1
- package/dist/commands/__tests__/pain-retry-maxTokens-flag.test.d.ts +0 -2
- package/dist/commands/__tests__/pain-retry-maxTokens-flag.test.d.ts.map +0 -1
- package/dist/commands/__tests__/pain-retry-maxTokens-flag.test.js +0 -60
- package/dist/commands/__tests__/pain-retry-maxTokens-flag.test.js.map +0 -1
- package/dist/commands/__tests__/rulecode-flag-wiring.test.d.ts +0 -21
- package/dist/commands/__tests__/rulecode-flag-wiring.test.d.ts.map +0 -1
- package/dist/commands/__tests__/rulecode-flag-wiring.test.js +0 -186
- package/dist/commands/__tests__/rulecode-flag-wiring.test.js.map +0 -1
- package/dist/commands/__tests__/rulecode-handler.test.d.ts +0 -16
- package/dist/commands/__tests__/rulecode-handler.test.d.ts.map +0 -1
- package/dist/commands/__tests__/rulecode-handler.test.js +0 -285
- package/dist/commands/__tests__/rulecode-handler.test.js.map +0 -1
- package/dist/commands/__tests__/run-rulehost-flag-wiring.test.d.ts +0 -24
- package/dist/commands/__tests__/run-rulehost-flag-wiring.test.d.ts.map +0 -1
- package/dist/commands/__tests__/run-rulehost-flag-wiring.test.js +0 -232
- package/dist/commands/__tests__/run-rulehost-flag-wiring.test.js.map +0 -1
- package/dist/commands/__tests__/runtime-activation-nextaction.test.d.ts +0 -15
- package/dist/commands/__tests__/runtime-activation-nextaction.test.d.ts.map +0 -1
- package/dist/commands/__tests__/runtime-activation-nextaction.test.js +0 -73
- package/dist/commands/__tests__/runtime-activation-nextaction.test.js.map +0 -1
- package/dist/commands/__tests__/runtime-probe-config.test.d.ts +0 -20
- package/dist/commands/__tests__/runtime-probe-config.test.d.ts.map +0 -1
- package/dist/commands/__tests__/runtime-probe-config.test.js +0 -389
- package/dist/commands/__tests__/runtime-probe-config.test.js.map +0 -1
- package/dist/commands/__tests__/telemetry-flag-wiring.test.d.ts +0 -9
- package/dist/commands/__tests__/telemetry-flag-wiring.test.d.ts.map +0 -1
- package/dist/commands/__tests__/telemetry-flag-wiring.test.js +0 -76
- package/dist/commands/__tests__/telemetry-flag-wiring.test.js.map +0 -1
- package/dist/commands/__tests__/version.test.d.ts +0 -2
- package/dist/commands/__tests__/version.test.d.ts.map +0 -1
- package/dist/commands/__tests__/version.test.js +0 -238
- package/dist/commands/__tests__/version.test.js.map +0 -1
- package/dist/commands/runtime-uat.guard.test.d.ts +0 -2
- package/dist/commands/runtime-uat.guard.test.d.ts.map +0 -1
- package/dist/commands/runtime-uat.guard.test.js +0 -153
- package/dist/commands/runtime-uat.guard.test.js.map +0 -1
- package/dist/services/__tests__/cli-output.test.d.ts +0 -18
- package/dist/services/__tests__/cli-output.test.d.ts.map +0 -1
- package/dist/services/__tests__/cli-output.test.js +0 -103
- package/dist/services/__tests__/cli-output.test.js.map +0 -1
- package/dist/services/__tests__/evaluator-runner-deps.test.d.ts +0 -2
- package/dist/services/__tests__/evaluator-runner-deps.test.d.ts.map +0 -1
- package/dist/services/__tests__/evaluator-runner-deps.test.js +0 -343
- package/dist/services/__tests__/evaluator-runner-deps.test.js.map +0 -1
- package/dist/services/__tests__/rulehost-readiness.test.d.ts +0 -2
- package/dist/services/__tests__/rulehost-readiness.test.d.ts.map +0 -1
- package/dist/services/__tests__/rulehost-readiness.test.js +0 -311
- package/dist/services/__tests__/rulehost-readiness.test.js.map +0 -1
- package/dist/services/__tests__/runtime-adapter-resolver.test.d.ts +0 -18
- package/dist/services/__tests__/runtime-adapter-resolver.test.d.ts.map +0 -1
- package/dist/services/__tests__/runtime-adapter-resolver.test.js +0 -673
- package/dist/services/__tests__/runtime-adapter-resolver.test.js.map +0 -1
- package/dist/utils/production-workspace-guard.test.d.ts +0 -2
- package/dist/utils/production-workspace-guard.test.d.ts.map +0 -1
- package/dist/utils/production-workspace-guard.test.js +0 -137
- package/dist/utils/production-workspace-guard.test.js.map +0 -1
- package/scripts/llm-dogfood.ts +0 -456
- package/scripts/migrate-illegal-expected-decision.ts +0 -252
- package/src/commands/__tests__/intent-flag-wiring.test.ts +0 -282
- package/src/commands/__tests__/legacy-cleanup.test.ts +0 -602
- package/src/commands/__tests__/mvp-smoke.test.ts +0 -300
- package/src/commands/__tests__/pain-retry-maxTokens-flag.test.ts +0 -73
- package/src/commands/__tests__/rulecode-flag-wiring.test.ts +0 -237
- package/src/commands/__tests__/rulecode-handler.test.ts +0 -369
- package/src/commands/__tests__/run-rulehost-flag-wiring.test.ts +0 -292
- package/src/commands/__tests__/runtime-activation-nextaction.test.ts +0 -81
- package/src/commands/__tests__/runtime-probe-config.test.ts +0 -432
- package/src/commands/__tests__/telemetry-flag-wiring.test.ts +0 -84
- package/src/commands/__tests__/version.test.ts +0 -251
- package/src/commands/admission-gate.ts +0 -30
- package/src/commands/artifact.ts +0 -82
- package/src/commands/build-trajectory-evidence.ts +0 -298
- package/src/commands/candidate.ts +0 -1260
- package/src/commands/codex-ingest-catchup.ts +0 -114
- package/src/commands/codex-ingest-quarantine.ts +0 -127
- package/src/commands/codex-reconcile.ts +0 -84
- package/src/commands/codex-setup.ts +0 -476
- package/src/commands/codex-worker.ts +0 -185
- package/src/commands/command-helpers.ts +0 -24
- package/src/commands/config-doctor.ts +0 -193
- package/src/commands/console.ts +0 -797
- package/src/commands/context.ts +0 -72
- package/src/commands/demo-story-a.ts +0 -241
- package/src/commands/diagnose.ts +0 -756
- package/src/commands/errors-list.ts +0 -441
- package/src/commands/evolution-tasks-list.ts +0 -48
- package/src/commands/evolution-tasks-show.ts +0 -62
- package/src/commands/flow.ts +0 -60
- package/src/commands/health-codex.ts +0 -576
- package/src/commands/health.ts +0 -315
- package/src/commands/history.ts +0 -63
- package/src/commands/intent.ts +0 -457
- package/src/commands/legacy-cleanup.ts +0 -531
- package/src/commands/legacy-import.ts +0 -104
- package/src/commands/mvp-smoke.ts +0 -160
- package/src/commands/pain-evidence.ts +0 -226
- package/src/commands/pain-list.ts +0 -239
- package/src/commands/pain-record.ts +0 -612
- package/src/commands/pain-retry.ts +0 -916
- package/src/commands/principles-stats.ts +0 -700
- package/src/commands/proven-channel-baseline.ts +0 -115
- package/src/commands/quality-scorecard.ts +0 -272
- package/src/commands/remediation-output.ts +0 -66
- package/src/commands/rulecode.ts +0 -465
- package/src/commands/run.ts +0 -89
- package/src/commands/runtime-activation.ts +0 -1629
- package/src/commands/runtime-artifact-repair.ts +0 -524
- package/src/commands/runtime-canary.ts +0 -395
- package/src/commands/runtime-compatibility-scan.ts +0 -105
- package/src/commands/runtime-diagnostics-export.ts +0 -229
- package/src/commands/runtime-features.ts +0 -153
- package/src/commands/runtime-gfi-snapshot.ts +0 -135
- package/src/commands/runtime-health-snapshot.ts +0 -108
- package/src/commands/runtime-init.ts +0 -429
- package/src/commands/runtime-internalization-enqueue-successors.ts +0 -530
- package/src/commands/runtime-internalization-integrity-repair.ts +0 -79
- package/src/commands/runtime-internalization-integrity.ts +0 -107
- package/src/commands/runtime-internalization-queue.ts +0 -135
- package/src/commands/runtime-internalization-retry.ts +0 -191
- package/src/commands/runtime-internalization-run-once.ts +0 -791
- package/src/commands/runtime-internalization-run-rulehost.ts +0 -749
- package/src/commands/runtime-internalization-wake-once.ts +0 -87
- package/src/commands/runtime-pain-flood-simulation.ts +0 -121
- package/src/commands/runtime-pruning.ts +0 -438
- package/src/commands/runtime-recovery-failed-tasks.ts +0 -258
- package/src/commands/runtime-recovery.ts +0 -109
- package/src/commands/runtime-synthetic-baseline.ts +0 -70
- package/src/commands/runtime-uat.guard.test.ts +0 -175
- package/src/commands/runtime-uat.ts +0 -380
- package/src/commands/runtime.ts +0 -473
- package/src/commands/samples-list.ts +0 -39
- package/src/commands/samples-review.ts +0 -36
- package/src/commands/task.ts +0 -271
- package/src/commands/telemetry.ts +0 -349
- package/src/commands/trace.ts +0 -174
- package/src/commands/trajectory-db-unavailable.ts +0 -19
- package/src/commands/trajectory.ts +0 -64
- package/src/commands/version.ts +0 -49
- package/src/config-reader.ts +0 -122
- package/src/index.ts +0 -1276
- package/src/legacy/legacy-import.ts +0 -179
- package/src/legacy/session-history-import.ts +0 -203
- package/src/resolve-workspace.ts +0 -106
- package/src/services/__tests__/cli-output.test.ts +0 -130
- package/src/services/__tests__/evaluator-runner-deps.test.ts +0 -382
- package/src/services/__tests__/rulehost-readiness.test.ts +0 -363
- package/src/services/__tests__/runtime-adapter-resolver.test.ts +0 -793
- package/src/services/cli-output.ts +0 -95
- package/src/services/config-doctor.ts +0 -697
- package/src/services/console-launcher.ts +0 -537
- package/src/services/demo-rule-compiler.ts +0 -40
- package/src/services/demo-story-a-runner.ts +0 -471
- package/src/services/mainline-snapshot-assembler.ts +0 -579
- package/src/services/pain-flood-simulation-runner.ts +0 -462
- package/src/services/pd-config-loader.ts +0 -433
- package/src/services/proven-channel-baseline-runner.ts +0 -157
- package/src/services/quality-scorecard/data-extractor.ts +0 -150
- package/src/services/quality-scorecard/local-evaluator.ts +0 -142
- package/src/services/quality-scorecard/strong-model-gate.ts +0 -202
- package/src/services/resolve-runtime-from-pd-config.ts +0 -230
- package/src/services/rulehost-pipeline-runner.ts +0 -1216
- package/src/services/rulehost-readiness.ts +0 -326
- package/src/services/runtime-adapter-resolver.ts +0 -364
- package/src/services/synthetic-baseline-runner.ts +0 -400
- package/src/services/version-report.ts +0 -253
- package/src/services/workspace-tool-semantics.ts +0 -26
- package/src/utils/path-security.ts +0 -96
- package/src/utils/production-workspace-guard.test.ts +0 -157
- package/src/utils/production-workspace-guard.ts +0 -210
- package/tests/bdd/cli-contract.steps.ts +0 -346
- package/tests/bdd/principles-stats.steps.ts +0 -211
- package/tests/bdd/support/gherkin-loader.ts +0 -147
- package/tests/bdd/support/repo-root.ts +0 -62
- package/tests/bdd/support/vitest-bdd.ts +0 -179
- package/tests/commands/admission-gate-coverage.test.ts +0 -79
- package/tests/commands/build-trajectory-evidence.test.ts +0 -508
- package/tests/commands/candidate-audit-repair.test.ts +0 -421
- package/tests/commands/candidate-intake.test.ts +0 -732
- package/tests/commands/candidate-internalization-backfill.test.ts +0 -548
- package/tests/commands/candidate-internalize-lineage.test.ts +0 -565
- package/tests/commands/candidate-internalize.test.ts +0 -299
- package/tests/commands/candidate-route.test.ts +0 -329
- package/tests/commands/candidate-show.test.ts +0 -95
- package/tests/commands/cli-command-tree.test.ts +0 -144
- package/tests/commands/cli-help-snapshot.test.ts +0 -155
- package/tests/commands/cli-skill-contract.test.ts +0 -121
- package/tests/commands/codex-consent-reversibility.steps.test.ts +0 -299
- package/tests/commands/codex-ingest-quarantine.test.ts +0 -136
- package/tests/commands/codex-setup.test.ts +0 -297
- package/tests/commands/codex-worker-daemon.test.ts +0 -95
- package/tests/commands/codex-worker-registration.test.ts +0 -207
- package/tests/commands/config-doctor.test.ts +0 -336
- package/tests/commands/console-launcher-edge-cases.test.ts +0 -388
- package/tests/commands/console-open.test.ts +0 -1381
- package/tests/commands/context.test.ts +0 -114
- package/tests/commands/demo-story-a.test.ts +0 -318
- package/tests/commands/diagnose.test.ts +0 -1803
- package/tests/commands/errors-list.test.ts +0 -679
- package/tests/commands/evolution-tasks-list.test.ts +0 -41
- package/tests/commands/evolution-tasks-show.test.ts +0 -46
- package/tests/commands/health-codex.test.ts +0 -349
- package/tests/commands/health-host-wiring.test.ts +0 -76
- package/tests/commands/health-reliability.test.ts +0 -99
- package/tests/commands/health.test.ts +0 -413
- package/tests/commands/intent.test.ts +0 -321
- package/tests/commands/legacy-cleanup.test.ts +0 -148
- package/tests/commands/pain-evidence.test.ts +0 -518
- package/tests/commands/pain-list.test.ts +0 -219
- package/tests/commands/pain-record-async.test.ts +0 -335
- package/tests/commands/pain-record-session-parser.test.ts +0 -228
- package/tests/commands/pain-record.test.ts +0 -851
- package/tests/commands/pain-retry.test.ts +0 -1121
- package/tests/commands/plugin-config-resolution-cutover.test.ts +0 -229
- package/tests/commands/pri-393-runtime-config-unification.test.ts +0 -443
- package/tests/commands/principles-stats-wiring.test.ts +0 -135
- package/tests/commands/principles-stats.test.ts +0 -274
- package/tests/commands/product-path-regression.test.ts +0 -86
- package/tests/commands/proven-channel-baseline.test.ts +0 -441
- package/tests/commands/rulecode.test.ts +0 -177
- package/tests/commands/run-rulehost-handler.test.ts +0 -908
- package/tests/commands/runtime-activation-approve-flag-wiring.test.ts +0 -227
- package/tests/commands/runtime-activation-deactivate-flag-wiring.test.ts +0 -167
- package/tests/commands/runtime-activation-dispatch-flag-wiring.test.ts +0 -262
- package/tests/commands/runtime-activation-governance-audit.test.ts +0 -95
- package/tests/commands/runtime-activation-list-flag-wiring.test.ts +0 -193
- package/tests/commands/runtime-activation-promote-flag-wiring.test.ts +0 -248
- package/tests/commands/runtime-activation-shadow-telemetry.test.ts +0 -130
- package/tests/commands/runtime-activation.test.ts +0 -2052
- package/tests/commands/runtime-artifact-repair-registration.test.ts +0 -74
- package/tests/commands/runtime-artifact-repair.test.ts +0 -404
- package/tests/commands/runtime-canary.test.ts +0 -430
- package/tests/commands/runtime-compatibility-scan.test.ts +0 -146
- package/tests/commands/runtime-diagnostics-export.test.ts +0 -175
- package/tests/commands/runtime-features.test.ts +0 -249
- package/tests/commands/runtime-health-snapshot.test.ts +0 -358
- package/tests/commands/runtime-init-empty-workspace.test.ts +0 -252
- package/tests/commands/runtime-init.test.ts +0 -420
- package/tests/commands/runtime-internalization-enqueue-successors.test.ts +0 -782
- package/tests/commands/runtime-internalization-integrity-repair.test.ts +0 -239
- package/tests/commands/runtime-internalization-integrity.test.ts +0 -140
- package/tests/commands/runtime-internalization-queue.test.ts +0 -380
- package/tests/commands/runtime-internalization-retry-owner-authority.test.ts +0 -431
- package/tests/commands/runtime-internalization-run-once-evaluator-parity.test.ts +0 -269
- package/tests/commands/runtime-internalization-run-once-language.test.ts +0 -303
- package/tests/commands/runtime-internalization-run-once-real-config.test.ts +0 -237
- package/tests/commands/runtime-internalization-run-once-rollout-parity.test.ts +0 -706
- package/tests/commands/runtime-internalization-run-once.test.ts +0 -1791
- package/tests/commands/runtime-internalization-wake-once.test.ts +0 -171
- package/tests/commands/runtime-internalization.test.ts +0 -53
- package/tests/commands/runtime-pain-flood-simulation.test.ts +0 -418
- package/tests/commands/runtime-pruning.test.ts +0 -694
- package/tests/commands/runtime-recovery-failed-tasks.test.ts +0 -328
- package/tests/commands/runtime-recovery.test.ts +0 -120
- package/tests/commands/runtime-synthetic-baseline.test.ts +0 -249
- package/tests/commands/runtime-uat.test.ts +0 -397
- package/tests/commands/runtime.test.ts +0 -392
- package/tests/commands/samples-list.test.ts +0 -43
- package/tests/commands/samples-review.test.ts +0 -41
- package/tests/commands/task.test.ts +0 -153
- package/tests/commands/telemetry.test.ts +0 -190
- package/tests/commands/trace.test.ts +0 -316
- package/tests/config-reader.test.ts +0 -143
- package/tests/e2e/candidate-intake-e2e.test.ts +0 -338
- package/tests/e2e/cli-full-flow.test.ts +0 -233
- package/tests/e2e/cross-package-acceptance.test.ts +0 -635
- package/tests/helpers/pd-cli-path.ts +0 -5
- package/tests/pd-cli-smoke.test.ts +0 -13
- package/tests/resolve-workspace.test.ts +0 -196
- package/tests/services/config-doctor-signal-health.test.ts +0 -109
- package/tests/services/console-launcher.test.ts +0 -114
- package/tests/services/demo-rule-compiler.test.ts +0 -242
- package/tests/services/mainline-snapshot-assembler.test.ts +0 -572
- package/tests/services/pd-config-loader.test.ts +0 -505
- package/tests/services/proven-channel-baseline-runner.test.ts +0 -30
- package/tests/services/quality-scorecard/strong-model-gate.test.ts +0 -133
- package/tests/services/resolve-runtime-from-pd-config.test.ts +0 -485
- package/tests/services/rulehost-pipeline-e2e.test.ts +0 -538
- package/tests/services/rulehost-pipeline-runner.test.ts +0 -1175
- package/tests/services/workspace-tool-semantics.test.ts +0 -76
- package/tests/utils/path-security.test.ts +0 -180
- package/tsconfig.json +0 -26
- package/vitest.config.ts +0 -9
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Legacy Compatibility Import — OpenClaw → PD Runtime v2
|
|
3
|
-
*
|
|
4
|
-
* ## Purpose
|
|
5
|
-
*
|
|
6
|
-
* This module is a **compatibility import path only**.
|
|
7
|
-
* It is NOT the authoritative retrieval path for M3 queries.
|
|
8
|
-
*
|
|
9
|
-
* It syncs diagnostician task data from OpenClaw's legacy JSON-based stores
|
|
10
|
-
* into the PD Runtime v2 SQLite store so that `pd trajectory`, `pd history`,
|
|
11
|
-
* and `pd context` commands have data to query against.
|
|
12
|
-
*
|
|
13
|
-
* **Authoritative path**: `workspace/.pd/state.db` (PD-owned SQLite)
|
|
14
|
-
* **This module's role**: migrate legacy `.state/diagnostician_tasks.json` →
|
|
15
|
-
* `workspace/.pd/state.db` (one-way sync, idempotent)
|
|
16
|
-
*
|
|
17
|
-
* ## Sync Sources
|
|
18
|
-
*
|
|
19
|
-
* - `.state/diagnostician_tasks.json` → tasks + runs tables
|
|
20
|
-
*
|
|
21
|
-
* ## Non-Goals
|
|
22
|
-
*
|
|
23
|
-
* This module does NOT:
|
|
24
|
-
* - Query raw OpenClaw `.state/` files for primary retrieval
|
|
25
|
-
* - Serve as the main path for trajectory/history/context commands
|
|
26
|
-
* - Own any PD task semantics
|
|
27
|
-
*
|
|
28
|
-
* ## Usage
|
|
29
|
-
*
|
|
30
|
-
* Call `syncOpenClawWorkspace(workspaceDir, connection)` once to import,
|
|
31
|
-
* then use `pd trajectory locate`, `pd history query`, `pd context build`
|
|
32
|
-
* which read from `workspace/.pd/state.db` directly.
|
|
33
|
-
*
|
|
34
|
-
* Idempotent: safe to call multiple times. Re-syncs latest state on every call.
|
|
35
|
-
*/
|
|
36
|
-
import * as fs from 'fs';
|
|
37
|
-
import * as path from 'path';
|
|
38
|
-
import type { SqliteConnection } from '@principles/core';
|
|
39
|
-
|
|
40
|
-
interface OpenClawDiagnosticianTask {
|
|
41
|
-
prompt: string;
|
|
42
|
-
createdAt: string;
|
|
43
|
-
status: 'pending' | 'completed';
|
|
44
|
-
reportMissingRetries?: number;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
interface OpenClawDiagnosticianStore {
|
|
48
|
-
tasks: Record<string, OpenClawDiagnosticianTask>;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
interface ParsedTaskFields {
|
|
52
|
-
sessionId: string;
|
|
53
|
-
painScore: number;
|
|
54
|
-
painSource: string;
|
|
55
|
-
painReason: string;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function readDiagnosticianStore(stateDir: string): OpenClawDiagnosticianStore {
|
|
59
|
-
const filePath = path.join(stateDir, 'diagnostician_tasks.json');
|
|
60
|
-
if (!fs.existsSync(filePath)) {
|
|
61
|
-
return { tasks: {} };
|
|
62
|
-
}
|
|
63
|
-
try {
|
|
64
|
-
const raw = fs.readFileSync(filePath, 'utf-8');
|
|
65
|
-
const parsed = JSON.parse(raw);
|
|
66
|
-
if (parsed && typeof parsed.tasks === 'object' && parsed.tasks !== null && !Array.isArray(parsed.tasks)) {
|
|
67
|
-
return parsed as OpenClawDiagnosticianStore;
|
|
68
|
-
}
|
|
69
|
-
return { tasks: {} };
|
|
70
|
-
} catch {
|
|
71
|
-
return { tasks: {} };
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function parsePrompt(taskId: string, prompt: string): ParsedTaskFields {
|
|
76
|
-
const sessionId =
|
|
77
|
-
/\*\*Session ID\*\*:\s*([^\n*]+)/.exec(prompt)?.[1]?.trim() ?? taskId;
|
|
78
|
-
const painScore =
|
|
79
|
-
parseInt(/\*\*Pain Score\*\*:\s*(\d+)/.exec(prompt)?.[1] ?? '0', 10);
|
|
80
|
-
const painSource =
|
|
81
|
-
/\*\*Source\*\*:\s*([^\n*]+)/.exec(prompt)?.[1]?.trim() ?? 'unknown';
|
|
82
|
-
const painReason =
|
|
83
|
-
/\*\*Reason\*\*:\s*([^\n*]+)/.exec(prompt)?.[1]?.trim() ?? '';
|
|
84
|
-
|
|
85
|
-
return { sessionId, painScore, painSource, painReason };
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function painScoreToSeverity(score: number): string {
|
|
89
|
-
if (score >= 80) return 'critical';
|
|
90
|
-
if (score >= 60) return 'high';
|
|
91
|
-
if (score >= 40) return 'medium';
|
|
92
|
-
return 'low';
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Sync all openclaw diagnostician tasks into the PD Runtime v2 SQLite store.
|
|
97
|
-
*
|
|
98
|
-
* For each task in diagnostician_tasks.json:
|
|
99
|
-
* - Upsert into tasks table (base fields + diagnostic_json blob)
|
|
100
|
-
* - Upsert a corresponding synthetic run into runs table
|
|
101
|
-
*
|
|
102
|
-
* Idempotent: existing records are updated, not duplicated.
|
|
103
|
-
*/
|
|
104
|
-
export async function syncOpenClawWorkspace(
|
|
105
|
-
workspaceDir: string,
|
|
106
|
-
connection: SqliteConnection,
|
|
107
|
-
): Promise<{ tasksSynced: number; runsSynced: number }> {
|
|
108
|
-
const stateDir = path.join(workspaceDir, '.state');
|
|
109
|
-
const store = readDiagnosticianStore(stateDir);
|
|
110
|
-
|
|
111
|
-
const db = connection.getDb();
|
|
112
|
-
let tasksSynced = 0;
|
|
113
|
-
let runsSynced = 0;
|
|
114
|
-
|
|
115
|
-
const upsertTask = db.prepare(`
|
|
116
|
-
INSERT INTO tasks (task_id, task_kind, status, created_at, updated_at, attempt_count, max_attempts, diagnostic_json)
|
|
117
|
-
VALUES (@taskId, 'diagnostician', @status, @createdAt, @updatedAt, 0, 3, @diagnosticJson)
|
|
118
|
-
ON CONFLICT(task_id) DO UPDATE SET
|
|
119
|
-
status = @status,
|
|
120
|
-
updated_at = @updatedAt,
|
|
121
|
-
diagnostic_json = @diagnosticJson
|
|
122
|
-
`);
|
|
123
|
-
|
|
124
|
-
const upsertRun = db.prepare(`
|
|
125
|
-
INSERT INTO runs (run_id, task_id, runtime_kind, execution_status, started_at, ended_at, attempt_number, created_at, updated_at)
|
|
126
|
-
VALUES (@runId, @taskId, 'openclaw', @executionStatus, @startedAt, @endedAt, 1, @createdAt, @updatedAt)
|
|
127
|
-
ON CONFLICT(run_id) DO UPDATE SET
|
|
128
|
-
execution_status = @executionStatus,
|
|
129
|
-
ended_at = @endedAt,
|
|
130
|
-
updated_at = @updatedAt
|
|
131
|
-
`);
|
|
132
|
-
|
|
133
|
-
const now = new Date().toISOString();
|
|
134
|
-
|
|
135
|
-
for (const [taskId, task] of Object.entries(store.tasks)) {
|
|
136
|
-
const { sessionId, painScore, painSource, painReason } = parsePrompt(taskId, task.prompt);
|
|
137
|
-
|
|
138
|
-
const status =
|
|
139
|
-
task.status === 'pending'
|
|
140
|
-
? 'pending'
|
|
141
|
-
: task.status === 'completed'
|
|
142
|
-
? 'succeeded'
|
|
143
|
-
: 'failed';
|
|
144
|
-
|
|
145
|
-
const severity = painScoreToSeverity(painScore);
|
|
146
|
-
const reasonSummary = painReason.length > 200 ? painReason.substring(0, 197) + '...' : painReason;
|
|
147
|
-
|
|
148
|
-
const diagnosticJson = JSON.stringify({
|
|
149
|
-
workspaceDir,
|
|
150
|
-
reasonSummary,
|
|
151
|
-
source: painSource,
|
|
152
|
-
severity,
|
|
153
|
-
sessionIdHint: sessionId !== taskId ? sessionId : null,
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
upsertTask.run({
|
|
157
|
-
taskId,
|
|
158
|
-
status,
|
|
159
|
-
createdAt: task.createdAt,
|
|
160
|
-
updatedAt: now,
|
|
161
|
-
diagnosticJson,
|
|
162
|
-
});
|
|
163
|
-
tasksSynced++;
|
|
164
|
-
|
|
165
|
-
const runId = `run_${taskId}_1`;
|
|
166
|
-
upsertRun.run({
|
|
167
|
-
runId,
|
|
168
|
-
taskId,
|
|
169
|
-
executionStatus: status === 'pending' ? 'queued' : 'succeeded',
|
|
170
|
-
startedAt: task.createdAt,
|
|
171
|
-
endedAt: status !== 'pending' ? now : null,
|
|
172
|
-
createdAt: task.createdAt,
|
|
173
|
-
updatedAt: now,
|
|
174
|
-
});
|
|
175
|
-
runsSynced++;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
return { tasksSynced, runsSynced };
|
|
179
|
-
}
|
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Session History Import — OpenClaw trajectory.db → PD Runtime v2
|
|
3
|
-
*
|
|
4
|
-
* Reads real conversation history from OpenClaw's trajectory.db and imports
|
|
5
|
-
* assistant_turns, user_turns, and tool_calls into PD-owned runtime-v2 runs table
|
|
6
|
-
* so that `pd history query` and `pd context build` return non-empty results.
|
|
7
|
-
*
|
|
8
|
-
* This is a COMPATIBILITY IMPORT — not authoritative retrieval.
|
|
9
|
-
* Primary retrieval always goes through `.pd/state.db` only.
|
|
10
|
-
*/
|
|
11
|
-
import Database from 'better-sqlite3';
|
|
12
|
-
import * as path from 'path';
|
|
13
|
-
|
|
14
|
-
interface OpenClawTrajectoryDb {
|
|
15
|
-
getAssistantTurns(sessionId: string): AssistantTurn[];
|
|
16
|
-
getUserTurns(sessionId: string): UserTurn[];
|
|
17
|
-
getToolCalls(sessionId: string): ToolCall[];
|
|
18
|
-
getSessionIds(): string[];
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
interface AssistantTurn {
|
|
22
|
-
id: number;
|
|
23
|
-
session_id: string;
|
|
24
|
-
run_id: string;
|
|
25
|
-
provider: string;
|
|
26
|
-
model: string;
|
|
27
|
-
sanitized_text: string;
|
|
28
|
-
created_at: string;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
interface UserTurn {
|
|
32
|
-
id: number;
|
|
33
|
-
session_id: string;
|
|
34
|
-
turn_index: number;
|
|
35
|
-
raw_text: string;
|
|
36
|
-
created_at: string;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
interface ToolCall {
|
|
40
|
-
id: number;
|
|
41
|
-
session_id: string;
|
|
42
|
-
tool_name: string;
|
|
43
|
-
outcome: string;
|
|
44
|
-
duration_ms: number | null;
|
|
45
|
-
exit_code: number | null;
|
|
46
|
-
error_type: string | null;
|
|
47
|
-
error_message: string | null;
|
|
48
|
-
created_at: string;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function openTrajectoryDb(dbPath: string): OpenClawTrajectoryDb {
|
|
52
|
-
const db = new Database(dbPath, { readonly: true });
|
|
53
|
-
|
|
54
|
-
return {
|
|
55
|
-
getAssistantTurns(sessionId: string): AssistantTurn[] {
|
|
56
|
-
return db
|
|
57
|
-
.prepare(
|
|
58
|
-
'SELECT id, session_id, run_id, provider, model, sanitized_text, created_at ' +
|
|
59
|
-
'FROM assistant_turns WHERE session_id = ? ORDER BY id ASC',
|
|
60
|
-
)
|
|
61
|
-
.all(sessionId) as AssistantTurn[];
|
|
62
|
-
},
|
|
63
|
-
|
|
64
|
-
getUserTurns(sessionId: string): UserTurn[] {
|
|
65
|
-
return db
|
|
66
|
-
.prepare(
|
|
67
|
-
'SELECT id, session_id, turn_index, raw_text, created_at ' +
|
|
68
|
-
'FROM user_turns WHERE session_id = ? ORDER BY id ASC',
|
|
69
|
-
)
|
|
70
|
-
.all(sessionId) as UserTurn[];
|
|
71
|
-
},
|
|
72
|
-
|
|
73
|
-
getToolCalls(sessionId: string): ToolCall[] {
|
|
74
|
-
return db
|
|
75
|
-
.prepare(
|
|
76
|
-
'SELECT id, session_id, tool_name, outcome, duration_ms, exit_code, ' +
|
|
77
|
-
'error_type, error_message, created_at ' +
|
|
78
|
-
'FROM tool_calls WHERE session_id = ? ORDER BY id ASC',
|
|
79
|
-
)
|
|
80
|
-
.all(sessionId) as ToolCall[];
|
|
81
|
-
},
|
|
82
|
-
|
|
83
|
-
getSessionIds(): string[] {
|
|
84
|
-
return (
|
|
85
|
-
db.prepare('SELECT session_id FROM sessions ORDER BY started_at DESC').all() as {
|
|
86
|
-
session_id: string;
|
|
87
|
-
}[]
|
|
88
|
-
).map((r) => r.session_id);
|
|
89
|
-
},
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Import session history from OpenClaw trajectory.db into PD runtime-v2 runs table.
|
|
95
|
-
*
|
|
96
|
-
* For each task that has a sessionIdHint in its diagnostic_json:
|
|
97
|
-
* 1. Look up the session in trajectory.db
|
|
98
|
-
* 2. Import assistant_turns, user_turns, tool_calls as entries
|
|
99
|
-
* 3. Upsert into runs table with full payload (JSON string)
|
|
100
|
-
*
|
|
101
|
-
* Idempotent: updates existing run records, does not duplicate.
|
|
102
|
-
*/
|
|
103
|
-
export async function importSessionHistory(
|
|
104
|
-
openclawWorkspaceDir: string,
|
|
105
|
-
pdWorkspaceDir: string,
|
|
106
|
-
getDb: () => Database.Database,
|
|
107
|
-
): Promise<{ sessionsProcessed: number; entriesImported: number }> {
|
|
108
|
-
const trajectoryPath = path.join(openclawWorkspaceDir, '.state', 'trajectory.db');
|
|
109
|
-
const trajectoryDb = openTrajectoryDb(trajectoryPath);
|
|
110
|
-
const db = getDb();
|
|
111
|
-
|
|
112
|
-
// Find all tasks with a sessionIdHint
|
|
113
|
-
const tasksWithSession = db
|
|
114
|
-
.prepare(
|
|
115
|
-
`SELECT task_id, json_extract(diagnostic_json, '$.sessionIdHint') as session_id
|
|
116
|
-
FROM tasks
|
|
117
|
-
WHERE json_extract(diagnostic_json, '$.sessionIdHint') IS NOT NULL
|
|
118
|
-
AND json_extract(diagnostic_json, '$.sessionIdHint') != ''`,
|
|
119
|
-
)
|
|
120
|
-
.all() as { task_id: string; session_id: string }[];
|
|
121
|
-
|
|
122
|
-
let sessionsProcessed = 0;
|
|
123
|
-
let entriesImported = 0;
|
|
124
|
-
|
|
125
|
-
const upsertRun = db.prepare(`
|
|
126
|
-
INSERT INTO runs (run_id, task_id, runtime_kind, execution_status, started_at, ended_at,
|
|
127
|
-
attempt_number, created_at, updated_at, input_payload, output_payload)
|
|
128
|
-
VALUES (@runId, @taskId, 'openclaw-history', @executionStatus, @startedAt, @endedAt,
|
|
129
|
-
1, @createdAt, @updatedAt, @inputPayload, @outputPayload)
|
|
130
|
-
ON CONFLICT(run_id) DO UPDATE SET
|
|
131
|
-
input_payload = @inputPayload,
|
|
132
|
-
output_payload = @outputPayload,
|
|
133
|
-
ended_at = @endedAt,
|
|
134
|
-
updated_at = @updatedAt
|
|
135
|
-
`);
|
|
136
|
-
|
|
137
|
-
const now = new Date().toISOString();
|
|
138
|
-
|
|
139
|
-
for (const { task_id, session_id } of tasksWithSession) {
|
|
140
|
-
// Verify session exists in trajectory.db
|
|
141
|
-
const assistantTurns = trajectoryDb.getAssistantTurns(session_id);
|
|
142
|
-
if (assistantTurns.length === 0) continue;
|
|
143
|
-
|
|
144
|
-
const userTurns = trajectoryDb.getUserTurns(session_id);
|
|
145
|
-
const toolCalls = trajectoryDb.getToolCalls(session_id);
|
|
146
|
-
|
|
147
|
-
// Use the latest timestamp from the session as ended_at
|
|
148
|
-
const [firstTurn] = assistantTurns;
|
|
149
|
-
const lastTurn = assistantTurns[assistantTurns.length - 1];
|
|
150
|
-
if (!firstTurn || !lastTurn) continue;
|
|
151
|
-
const lastTimestamp = lastTurn.created_at;
|
|
152
|
-
|
|
153
|
-
// Build input (user turns + tool calls) and output (assistant turns) payloads
|
|
154
|
-
const inputPayload = JSON.stringify({
|
|
155
|
-
type: 'session_history',
|
|
156
|
-
sessionId: session_id,
|
|
157
|
-
userTurns: userTurns.map((t) => ({
|
|
158
|
-
turnIndex: t.turn_index,
|
|
159
|
-
text: t.raw_text,
|
|
160
|
-
ts: t.created_at,
|
|
161
|
-
})),
|
|
162
|
-
toolCalls: toolCalls.map((t) => ({
|
|
163
|
-
toolName: t.tool_name,
|
|
164
|
-
outcome: t.outcome,
|
|
165
|
-
durationMs: t.duration_ms,
|
|
166
|
-
exitCode: t.exit_code,
|
|
167
|
-
errorType: t.error_type,
|
|
168
|
-
errorMessage: t.error_message,
|
|
169
|
-
ts: t.created_at,
|
|
170
|
-
})),
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
const outputPayload = JSON.stringify({
|
|
174
|
-
type: 'assistant_turns',
|
|
175
|
-
sessionId: session_id,
|
|
176
|
-
turns: assistantTurns.map((t) => ({
|
|
177
|
-
provider: t.provider,
|
|
178
|
-
model: t.model,
|
|
179
|
-
text: t.sanitized_text,
|
|
180
|
-
ts: t.created_at,
|
|
181
|
-
})),
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
const runId = `run_${task_id}_history_1`;
|
|
185
|
-
|
|
186
|
-
upsertRun.run({
|
|
187
|
-
runId,
|
|
188
|
-
taskId: task_id,
|
|
189
|
-
executionStatus: 'succeeded',
|
|
190
|
-
startedAt: firstTurn.created_at,
|
|
191
|
-
endedAt: lastTimestamp,
|
|
192
|
-
createdAt: firstTurn.created_at,
|
|
193
|
-
updatedAt: now,
|
|
194
|
-
inputPayload,
|
|
195
|
-
outputPayload,
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
entriesImported += assistantTurns.length + userTurns.length + toolCalls.length;
|
|
199
|
-
sessionsProcessed++;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
return { sessionsProcessed, entriesImported };
|
|
203
|
-
}
|
package/src/resolve-workspace.ts
DELETED
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Resolve the active workspace directory.
|
|
3
|
-
*
|
|
4
|
-
* Resolution chain (highest priority first):
|
|
5
|
-
* 1. Explicit --workspace flag
|
|
6
|
-
* 2. PD_WORKSPACE_DIR environment variable
|
|
7
|
-
* 3. workspace.default from discovered .pd/config.yaml
|
|
8
|
-
* 4. Throw Error (preserve current behavior for unconfigured setups)
|
|
9
|
-
*
|
|
10
|
-
* When the resolved path differs from workspace.default in config,
|
|
11
|
-
* a warning is emitted to stderr.
|
|
12
|
-
*
|
|
13
|
-
* @throws Error if no workspace directory can be determined.
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
import * as path from 'path';
|
|
17
|
-
import { discoverWorkspaceDefault } from './services/pd-config-loader.js';
|
|
18
|
-
import { assertSafeDirectoryRoot } from './utils/path-security.js';
|
|
19
|
-
|
|
20
|
-
/** Environment variable name for workspace directory. */
|
|
21
|
-
export const WORKSPACE_ENV = 'PD_WORKSPACE_DIR';
|
|
22
|
-
|
|
23
|
-
// ── Internal helpers ────────────────────────────────────────────────────────
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Normalize a path to forward slashes for cross-platform string comparison.
|
|
27
|
-
*
|
|
28
|
-
* Comparison-only helper: it never resolves against the filesystem and never
|
|
29
|
-
* feeds a filesystem operation, so it intentionally uses `path.normalize`
|
|
30
|
-
* (pure string normalization) instead of `path.resolve`. Callers compare two
|
|
31
|
-
* paths for equality after normalization; the workspace root itself is
|
|
32
|
-
* validated by `assertWorkspaceDirInside` before any IO uses it.
|
|
33
|
-
*/
|
|
34
|
-
function normalizePath(p: string): string {
|
|
35
|
-
return path.normalize(p).replace(/\\/g, '/');
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/** Emit workspace warnings to stderr. */
|
|
39
|
-
function emitWarning(msg: string): void {
|
|
40
|
-
process.stderr.write(`[PD:workspace] WARNING: ${msg}\n`);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Validate an operator-supplied workspace root before it is used as an IO
|
|
45
|
-
* root. Delegates to the shared canonical-root validator (empty, parent
|
|
46
|
-
* traversal, filesystem root). Returns nothing; callers keep the original
|
|
47
|
-
* value so downstream resolution semantics are unchanged.
|
|
48
|
-
*/
|
|
49
|
-
function assertWorkspaceDirInside(p: string, source: string): void {
|
|
50
|
-
assertSafeDirectoryRoot(p, source);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/** Emit a warning when an explicit override differs from config default. */
|
|
54
|
-
function emitWarningIfDiffers(
|
|
55
|
-
override: string,
|
|
56
|
-
configDefault: string | undefined,
|
|
57
|
-
discovered: { configPath?: string } | null,
|
|
58
|
-
): void {
|
|
59
|
-
if (configDefault && normalizePath(override) !== normalizePath(configDefault)) {
|
|
60
|
-
emitWarning(
|
|
61
|
-
`"${override}" differs from config default "${configDefault}" ` +
|
|
62
|
-
`(source: ${discovered?.configPath}). Using explicit override. ` +
|
|
63
|
-
`Consider updating workspace.default in config.`,
|
|
64
|
-
);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// ── Public API ──────────────────────────────────────────────────────────────
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Resolve the active workspace directory.
|
|
72
|
-
*
|
|
73
|
-
* API surface: `(workspaceDir?: string): string`
|
|
74
|
-
* All 13 command files and 20 test mocks rely on this exact signature.
|
|
75
|
-
*/
|
|
76
|
-
export function resolveWorkspaceDir(workspaceDir?: string): string {
|
|
77
|
-
// Step 1: Discover config-based default (runs always for warning comparison)
|
|
78
|
-
const discovered = discoverWorkspaceDefault();
|
|
79
|
-
const configDefault = discovered?.workspaceDefault;
|
|
80
|
-
|
|
81
|
-
// Step 2: Check --workspace flag (highest priority)
|
|
82
|
-
if (workspaceDir) {
|
|
83
|
-
assertWorkspaceDirInside(workspaceDir, '--workspace');
|
|
84
|
-
emitWarningIfDiffers(workspaceDir, configDefault, discovered);
|
|
85
|
-
return workspaceDir;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// Step 3: Check PD_WORKSPACE_DIR env var
|
|
89
|
-
const envWorkspace = process.env.PD_WORKSPACE_DIR?.trim();
|
|
90
|
-
if (envWorkspace) {
|
|
91
|
-
assertWorkspaceDirInside(envWorkspace, WORKSPACE_ENV);
|
|
92
|
-
emitWarningIfDiffers(envWorkspace, configDefault, discovered);
|
|
93
|
-
return envWorkspace;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// Step 4: Use discovered config default
|
|
97
|
-
if (configDefault) {
|
|
98
|
-
assertWorkspaceDirInside(configDefault, 'workspace.default');
|
|
99
|
-
return configDefault;
|
|
100
|
-
}
|
|
101
|
-
// Step 5: No resolution possible — throw (preserves current behavior)
|
|
102
|
-
throw new Error(
|
|
103
|
-
'No workspace directory configured. Set --workspace <path>, ' +
|
|
104
|
-
'PD_WORKSPACE_DIR environment variable, or add workspace.default to .pd/config.yaml.',
|
|
105
|
-
);
|
|
106
|
-
}
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* PRI-432: Tests for shared CLI output module.
|
|
3
|
-
*
|
|
4
|
-
* Extracts common output patterns from:
|
|
5
|
-
* - runtime-features.ts (JSON/text emit + exit code)
|
|
6
|
-
* - runtime-recovery.ts (dry-run/confirm conflict + JSON/text emit)
|
|
7
|
-
* - runtime-internalization-integrity-repair.ts (conflict + error catch + JSON/text emit)
|
|
8
|
-
*
|
|
9
|
-
* TDD flow: these tests are RED until cli-output.ts is implemented.
|
|
10
|
-
*
|
|
11
|
-
* ERR refs:
|
|
12
|
-
* - ERR-001 (no any): all types explicit
|
|
13
|
-
* - ERR-005 (no as bypass): no type casts
|
|
14
|
-
* - ERR-009 (fail-loud): emitError returns exit code, does not swallow
|
|
15
|
-
* - ERR-002 (graceful degradation with reason): all error paths include reason + nextAction
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
19
|
-
|
|
20
|
-
const { emitResult, emitFlagConflict, emitError } = await import('../cli-output.js');
|
|
21
|
-
|
|
22
|
-
describe('cli-output module (PRI-432)', () => {
|
|
23
|
-
let consoleLogSpy: ReturnType<typeof vi.spyOn>;
|
|
24
|
-
let consoleErrorSpy: ReturnType<typeof vi.spyOn>;
|
|
25
|
-
|
|
26
|
-
beforeEach(() => {
|
|
27
|
-
vi.clearAllMocks();
|
|
28
|
-
consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => undefined);
|
|
29
|
-
consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => undefined);
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
// ── emitResult ──────────────────────────────────────────────────────────
|
|
33
|
-
|
|
34
|
-
describe('emitResult', () => {
|
|
35
|
-
it('emits JSON to stdout when json=true', () => {
|
|
36
|
-
const output = { status: 'ok', count: 5 };
|
|
37
|
-
const formatText = (o: typeof output) => `Status: ${o.status}`;
|
|
38
|
-
|
|
39
|
-
emitResult(output, { json: true, formatText });
|
|
40
|
-
|
|
41
|
-
expect(consoleLogSpy).toHaveBeenCalledTimes(1);
|
|
42
|
-
const emitted = JSON.parse(consoleLogSpy.mock.calls[0][0] as string);
|
|
43
|
-
expect(emitted).toEqual(output);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it('emits text to stdout when json=false', () => {
|
|
47
|
-
const output = { status: 'ok', count: 5 };
|
|
48
|
-
const formatText = (o: typeof output) => `Status: ${o.status}`;
|
|
49
|
-
|
|
50
|
-
emitResult(output, { json: false, formatText });
|
|
51
|
-
|
|
52
|
-
expect(consoleLogSpy).toHaveBeenCalledWith('Status: ok');
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it('uses formatText callback for text output', () => {
|
|
56
|
-
const output = { status: 'failed', reason: 'bad config' };
|
|
57
|
-
const formatText = (o: typeof output) => `ERROR: ${o.reason}`;
|
|
58
|
-
|
|
59
|
-
emitResult(output, { json: false, formatText });
|
|
60
|
-
|
|
61
|
-
expect(consoleLogSpy).toHaveBeenCalledWith('ERROR: bad config');
|
|
62
|
-
});
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
// ── emitFlagConflict ────────────────────────────────────────────────────
|
|
66
|
-
|
|
67
|
-
describe('emitFlagConflict', () => {
|
|
68
|
-
it('emits JSON error to stdout when json=true', () => {
|
|
69
|
-
const exitCode = emitFlagConflict({ json: true });
|
|
70
|
-
|
|
71
|
-
expect(exitCode).toBe(1);
|
|
72
|
-
expect(consoleLogSpy).toHaveBeenCalledTimes(1);
|
|
73
|
-
const emitted = JSON.parse(consoleLogSpy.mock.calls[0][0] as string);
|
|
74
|
-
expect(emitted.ok).toBe(false);
|
|
75
|
-
expect(emitted.reason).toContain('mutually exclusive');
|
|
76
|
-
expect(emitted.nextAction).toContain('--dry-run');
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
it('emits text error to stderr when json=false', () => {
|
|
80
|
-
const exitCode = emitFlagConflict({ json: false });
|
|
81
|
-
|
|
82
|
-
expect(exitCode).toBe(1);
|
|
83
|
-
expect(consoleErrorSpy).toHaveBeenCalledTimes(1);
|
|
84
|
-
const msg = consoleErrorSpy.mock.calls[0][0] as string;
|
|
85
|
-
expect(msg).toContain('mutually exclusive');
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
it('always returns exit code 1', () => {
|
|
89
|
-
expect(emitFlagConflict({ json: true })).toBe(1);
|
|
90
|
-
expect(emitFlagConflict({ json: false })).toBe(1);
|
|
91
|
-
});
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
// ── emitError ───────────────────────────────────────────────────────────
|
|
95
|
-
|
|
96
|
-
describe('emitError', () => {
|
|
97
|
-
it('emits JSON error to stdout when json=true', () => {
|
|
98
|
-
const err = new Error('DB connection failed');
|
|
99
|
-
const exitCode = emitError(err, { json: true, nextAction: 'Check DB connectivity' });
|
|
100
|
-
|
|
101
|
-
expect(exitCode).toBe(1);
|
|
102
|
-
expect(consoleLogSpy).toHaveBeenCalledTimes(1);
|
|
103
|
-
const emitted = JSON.parse(consoleLogSpy.mock.calls[0][0] as string);
|
|
104
|
-
expect(emitted.ok).toBe(false);
|
|
105
|
-
expect(emitted.reason).toBe('DB connection failed');
|
|
106
|
-
expect(emitted.nextAction).toBe('Check DB connectivity');
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
it('emits text error to stderr when json=false', () => {
|
|
110
|
-
const err = new Error('DB connection failed');
|
|
111
|
-
const exitCode = emitError(err, { json: false, nextAction: 'Check DB connectivity' });
|
|
112
|
-
|
|
113
|
-
expect(exitCode).toBe(1);
|
|
114
|
-
expect(consoleErrorSpy).toHaveBeenCalledWith('Error: DB connection failed');
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
it('handles non-Error throwables via String()', () => {
|
|
118
|
-
const exitCode = emitError('string error', { json: true, nextAction: 'retry' });
|
|
119
|
-
|
|
120
|
-
expect(exitCode).toBe(1);
|
|
121
|
-
const emitted = JSON.parse(consoleLogSpy.mock.calls[0][0] as string);
|
|
122
|
-
expect(emitted.reason).toBe('string error');
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
it('always returns exit code 1', () => {
|
|
126
|
-
expect(emitError(new Error('x'), { json: true, nextAction: 'y' })).toBe(1);
|
|
127
|
-
expect(emitError(new Error('x'), { json: false, nextAction: 'y' })).toBe(1);
|
|
128
|
-
});
|
|
129
|
-
});
|
|
130
|
-
});
|