@principles/pd-cli 1.73.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/README.md +90 -0
- package/dist/commands/artifact.d.ts +14 -0
- package/dist/commands/artifact.d.ts.map +1 -0
- package/dist/commands/artifact.js +67 -0
- package/dist/commands/artifact.js.map +1 -0
- package/dist/commands/candidate.d.ts +83 -0
- package/dist/commands/candidate.d.ts.map +1 -0
- package/dist/commands/candidate.js +891 -0
- package/dist/commands/candidate.js.map +1 -0
- package/dist/commands/central-sync.d.ts +10 -0
- package/dist/commands/central-sync.d.ts.map +1 -0
- package/dist/commands/central-sync.js +32 -0
- package/dist/commands/central-sync.js.map +1 -0
- package/dist/commands/console.d.ts +9 -0
- package/dist/commands/console.d.ts.map +1 -0
- package/dist/commands/console.js +114 -0
- package/dist/commands/console.js.map +1 -0
- package/dist/commands/context.d.ts +7 -0
- package/dist/commands/context.d.ts.map +1 -0
- package/dist/commands/context.js +55 -0
- package/dist/commands/context.js.map +1 -0
- package/dist/commands/demo-story-a.d.ts +12 -0
- package/dist/commands/demo-story-a.d.ts.map +1 -0
- package/dist/commands/demo-story-a.js +175 -0
- package/dist/commands/demo-story-a.js.map +1 -0
- package/dist/commands/diagnose.d.ts +35 -0
- package/dist/commands/diagnose.d.ts.map +1 -0
- package/dist/commands/diagnose.js +390 -0
- package/dist/commands/diagnose.js.map +1 -0
- package/dist/commands/evolution-tasks-list.d.ts +15 -0
- package/dist/commands/evolution-tasks-list.d.ts.map +1 -0
- package/dist/commands/evolution-tasks-list.js +34 -0
- package/dist/commands/evolution-tasks-list.js.map +1 -0
- package/dist/commands/evolution-tasks-show.d.ts +14 -0
- package/dist/commands/evolution-tasks-show.d.ts.map +1 -0
- package/dist/commands/evolution-tasks-show.js +52 -0
- package/dist/commands/evolution-tasks-show.js.map +1 -0
- package/dist/commands/flow.d.ts +7 -0
- package/dist/commands/flow.d.ts.map +1 -0
- package/dist/commands/flow.js +57 -0
- package/dist/commands/flow.js.map +1 -0
- package/dist/commands/health.d.ts +16 -0
- package/dist/commands/health.d.ts.map +1 -0
- package/dist/commands/health.js +150 -0
- package/dist/commands/health.js.map +1 -0
- package/dist/commands/history.d.ts +11 -0
- package/dist/commands/history.d.ts.map +1 -0
- package/dist/commands/history.js +50 -0
- package/dist/commands/history.js.map +1 -0
- package/dist/commands/legacy-cleanup.d.ts +27 -0
- package/dist/commands/legacy-cleanup.d.ts.map +1 -0
- package/dist/commands/legacy-cleanup.js +171 -0
- package/dist/commands/legacy-cleanup.js.map +1 -0
- package/dist/commands/legacy-import.d.ts +7 -0
- package/dist/commands/legacy-import.d.ts.map +1 -0
- package/dist/commands/legacy-import.js +86 -0
- package/dist/commands/legacy-import.js.map +1 -0
- package/dist/commands/pain-record.d.ts +10 -0
- package/dist/commands/pain-record.d.ts.map +1 -0
- package/dist/commands/pain-record.js +162 -0
- package/dist/commands/pain-record.js.map +1 -0
- package/dist/commands/proven-channel-baseline.d.ts +12 -0
- package/dist/commands/proven-channel-baseline.d.ts.map +1 -0
- package/dist/commands/proven-channel-baseline.js +97 -0
- package/dist/commands/proven-channel-baseline.js.map +1 -0
- package/dist/commands/remediation-output.d.ts +40 -0
- package/dist/commands/remediation-output.d.ts.map +1 -0
- package/dist/commands/remediation-output.js +23 -0
- package/dist/commands/remediation-output.js.map +1 -0
- package/dist/commands/run.d.ts +10 -0
- package/dist/commands/run.d.ts.map +1 -0
- package/dist/commands/run.js +68 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/commands/runtime-activation.d.ts +11 -0
- package/dist/commands/runtime-activation.d.ts.map +1 -0
- package/dist/commands/runtime-activation.js +150 -0
- package/dist/commands/runtime-activation.js.map +1 -0
- package/dist/commands/runtime-canary.d.ts +30 -0
- package/dist/commands/runtime-canary.d.ts.map +1 -0
- package/dist/commands/runtime-canary.js +343 -0
- package/dist/commands/runtime-canary.js.map +1 -0
- package/dist/commands/runtime-diagnostics-export.d.ts +20 -0
- package/dist/commands/runtime-diagnostics-export.d.ts.map +1 -0
- package/dist/commands/runtime-diagnostics-export.js +177 -0
- package/dist/commands/runtime-diagnostics-export.js.map +1 -0
- package/dist/commands/runtime-features.d.ts +26 -0
- package/dist/commands/runtime-features.d.ts.map +1 -0
- package/dist/commands/runtime-features.js +70 -0
- package/dist/commands/runtime-features.js.map +1 -0
- package/dist/commands/runtime-gfi-snapshot.d.ts +7 -0
- package/dist/commands/runtime-gfi-snapshot.d.ts.map +1 -0
- package/dist/commands/runtime-gfi-snapshot.js +101 -0
- package/dist/commands/runtime-gfi-snapshot.js.map +1 -0
- package/dist/commands/runtime-health-snapshot.d.ts +7 -0
- package/dist/commands/runtime-health-snapshot.d.ts.map +1 -0
- package/dist/commands/runtime-health-snapshot.js +93 -0
- package/dist/commands/runtime-health-snapshot.js.map +1 -0
- package/dist/commands/runtime-idle-trigger.d.ts +12 -0
- package/dist/commands/runtime-idle-trigger.d.ts.map +1 -0
- package/dist/commands/runtime-idle-trigger.js +102 -0
- package/dist/commands/runtime-idle-trigger.js.map +1 -0
- package/dist/commands/runtime-internalization-enqueue-successors.d.ts +9 -0
- package/dist/commands/runtime-internalization-enqueue-successors.d.ts.map +1 -0
- package/dist/commands/runtime-internalization-enqueue-successors.js +393 -0
- package/dist/commands/runtime-internalization-enqueue-successors.js.map +1 -0
- package/dist/commands/runtime-internalization-integrity-repair.d.ts +9 -0
- package/dist/commands/runtime-internalization-integrity-repair.d.ts.map +1 -0
- package/dist/commands/runtime-internalization-integrity-repair.js +54 -0
- package/dist/commands/runtime-internalization-integrity-repair.js.map +1 -0
- package/dist/commands/runtime-internalization-integrity.d.ts +7 -0
- package/dist/commands/runtime-internalization-integrity.d.ts.map +1 -0
- package/dist/commands/runtime-internalization-integrity.js +53 -0
- package/dist/commands/runtime-internalization-integrity.js.map +1 -0
- package/dist/commands/runtime-internalization-queue.d.ts +7 -0
- package/dist/commands/runtime-internalization-queue.d.ts.map +1 -0
- package/dist/commands/runtime-internalization-queue.js +85 -0
- package/dist/commands/runtime-internalization-queue.js.map +1 -0
- package/dist/commands/runtime-internalization-run-once.d.ts +12 -0
- package/dist/commands/runtime-internalization-run-once.d.ts.map +1 -0
- package/dist/commands/runtime-internalization-run-once.js +546 -0
- package/dist/commands/runtime-internalization-run-once.js.map +1 -0
- package/dist/commands/runtime-internalization-wake-once.d.ts +8 -0
- package/dist/commands/runtime-internalization-wake-once.d.ts.map +1 -0
- package/dist/commands/runtime-internalization-wake-once.js +72 -0
- package/dist/commands/runtime-internalization-wake-once.js.map +1 -0
- package/dist/commands/runtime-pain-flood-simulation.d.ts +10 -0
- package/dist/commands/runtime-pain-flood-simulation.d.ts.map +1 -0
- package/dist/commands/runtime-pain-flood-simulation.js +104 -0
- package/dist/commands/runtime-pain-flood-simulation.js.map +1 -0
- package/dist/commands/runtime-pruning.d.ts +45 -0
- package/dist/commands/runtime-pruning.d.ts.map +1 -0
- package/dist/commands/runtime-pruning.js +355 -0
- package/dist/commands/runtime-pruning.js.map +1 -0
- package/dist/commands/runtime-recovery.d.ts +9 -0
- package/dist/commands/runtime-recovery.d.ts.map +1 -0
- package/dist/commands/runtime-recovery.js +94 -0
- package/dist/commands/runtime-recovery.js.map +1 -0
- package/dist/commands/runtime-synthetic-baseline.d.ts +7 -0
- package/dist/commands/runtime-synthetic-baseline.d.ts.map +1 -0
- package/dist/commands/runtime-synthetic-baseline.js +59 -0
- package/dist/commands/runtime-synthetic-baseline.js.map +1 -0
- package/dist/commands/runtime-uat.d.ts +52 -0
- package/dist/commands/runtime-uat.d.ts.map +1 -0
- package/dist/commands/runtime-uat.js +274 -0
- package/dist/commands/runtime-uat.js.map +1 -0
- package/dist/commands/runtime.d.ts +20 -0
- package/dist/commands/runtime.d.ts.map +1 -0
- package/dist/commands/runtime.js +256 -0
- package/dist/commands/runtime.js.map +1 -0
- package/dist/commands/samples-list.d.ts +11 -0
- package/dist/commands/samples-list.d.ts.map +1 -0
- package/dist/commands/samples-list.js +37 -0
- package/dist/commands/samples-list.js.map +1 -0
- package/dist/commands/samples-review.d.ts +14 -0
- package/dist/commands/samples-review.d.ts.map +1 -0
- package/dist/commands/samples-review.js +22 -0
- package/dist/commands/samples-review.js.map +1 -0
- package/dist/commands/task.d.ts +14 -0
- package/dist/commands/task.d.ts.map +1 -0
- package/dist/commands/task.js +92 -0
- package/dist/commands/task.js.map +1 -0
- package/dist/commands/trace.d.ts +19 -0
- package/dist/commands/trace.d.ts.map +1 -0
- package/dist/commands/trace.js +154 -0
- package/dist/commands/trace.js.map +1 -0
- package/dist/commands/trajectory.d.ts +11 -0
- package/dist/commands/trajectory.d.ts.map +1 -0
- package/dist/commands/trajectory.js +47 -0
- package/dist/commands/trajectory.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +736 -0
- package/dist/index.js.map +1 -0
- package/dist/legacy/legacy-import.d.ts +15 -0
- package/dist/legacy/legacy-import.d.ts.map +1 -0
- package/dist/legacy/legacy-import.js +141 -0
- package/dist/legacy/legacy-import.js.map +1 -0
- package/dist/legacy/session-history-import.d.ts +26 -0
- package/dist/legacy/session-history-import.d.ts.map +1 -0
- package/dist/legacy/session-history-import.js +151 -0
- package/dist/legacy/session-history-import.js.map +1 -0
- package/dist/principle-tree-ledger-adapter.d.ts +12 -0
- package/dist/principle-tree-ledger-adapter.d.ts.map +1 -0
- package/dist/principle-tree-ledger-adapter.js +12 -0
- package/dist/principle-tree-ledger-adapter.js.map +1 -0
- package/dist/resolve-workspace.d.ts +12 -0
- package/dist/resolve-workspace.d.ts.map +1 -0
- package/dist/resolve-workspace.js +20 -0
- package/dist/resolve-workspace.js.map +1 -0
- package/dist/services/demo-story-a-runner.d.ts +8 -0
- package/dist/services/demo-story-a-runner.d.ts.map +1 -0
- package/dist/services/demo-story-a-runner.js +369 -0
- package/dist/services/demo-story-a-runner.js.map +1 -0
- package/dist/services/feature-flag-loader.d.ts +6 -0
- package/dist/services/feature-flag-loader.d.ts.map +1 -0
- package/dist/services/feature-flag-loader.js +54 -0
- package/dist/services/feature-flag-loader.js.map +1 -0
- package/dist/services/pain-flood-simulation-runner.d.ts +10 -0
- package/dist/services/pain-flood-simulation-runner.d.ts.map +1 -0
- package/dist/services/pain-flood-simulation-runner.js +289 -0
- package/dist/services/pain-flood-simulation-runner.js.map +1 -0
- package/dist/services/proven-channel-baseline-runner.d.ts +12 -0
- package/dist/services/proven-channel-baseline-runner.d.ts.map +1 -0
- package/dist/services/proven-channel-baseline-runner.js +114 -0
- package/dist/services/proven-channel-baseline-runner.js.map +1 -0
- package/dist/services/synthetic-baseline-runner.d.ts +8 -0
- package/dist/services/synthetic-baseline-runner.d.ts.map +1 -0
- package/dist/services/synthetic-baseline-runner.js +251 -0
- package/dist/services/synthetic-baseline-runner.js.map +1 -0
- package/package.json +35 -0
- package/src/commands/artifact.ts +82 -0
- package/src/commands/candidate.ts +1117 -0
- package/src/commands/central-sync.ts +44 -0
- package/src/commands/console.ts +121 -0
- package/src/commands/context.ts +72 -0
- package/src/commands/demo-story-a.ts +195 -0
- package/src/commands/diagnose.ts +452 -0
- package/src/commands/evolution-tasks-list.ts +44 -0
- package/src/commands/evolution-tasks-show.ts +60 -0
- package/src/commands/flow.ts +60 -0
- package/src/commands/health.ts +189 -0
- package/src/commands/history.ts +63 -0
- package/src/commands/legacy-cleanup.ts +206 -0
- package/src/commands/legacy-import.ts +104 -0
- package/src/commands/pain-record.ts +167 -0
- package/src/commands/proven-channel-baseline.ts +113 -0
- package/src/commands/remediation-output.ts +66 -0
- package/src/commands/run.ts +89 -0
- package/src/commands/runtime-activation.ts +176 -0
- package/src/commands/runtime-canary.ts +371 -0
- package/src/commands/runtime-diagnostics-export.ts +229 -0
- package/src/commands/runtime-features.ts +103 -0
- package/src/commands/runtime-gfi-snapshot.ts +135 -0
- package/src/commands/runtime-health-snapshot.ts +106 -0
- package/src/commands/runtime-internalization-enqueue-successors.ts +479 -0
- package/src/commands/runtime-internalization-integrity-repair.ts +69 -0
- package/src/commands/runtime-internalization-integrity.ts +63 -0
- package/src/commands/runtime-internalization-queue.ts +106 -0
- package/src/commands/runtime-internalization-run-once.ts +658 -0
- package/src/commands/runtime-internalization-wake-once.ts +87 -0
- package/src/commands/runtime-pain-flood-simulation.ts +121 -0
- package/src/commands/runtime-pruning.ts +438 -0
- package/src/commands/runtime-recovery.ts +107 -0
- package/src/commands/runtime-synthetic-baseline.ts +70 -0
- package/src/commands/runtime-uat.ts +339 -0
- package/src/commands/runtime.ts +281 -0
- package/src/commands/samples-list.ts +43 -0
- package/src/commands/samples-review.ts +32 -0
- package/src/commands/task.ts +130 -0
- package/src/commands/trace.ts +174 -0
- package/src/commands/trajectory.ts +64 -0
- package/src/index.ts +829 -0
- package/src/legacy/legacy-import.ts +179 -0
- package/src/legacy/session-history-import.ts +231 -0
- package/src/principle-tree-ledger-adapter.ts +13 -0
- package/src/resolve-workspace.ts +20 -0
- package/src/services/demo-story-a-runner.ts +472 -0
- package/src/services/feature-flag-loader.ts +73 -0
- package/src/services/pain-flood-simulation-runner.ts +354 -0
- package/src/services/proven-channel-baseline-runner.ts +150 -0
- package/src/services/synthetic-baseline-runner.ts +291 -0
- package/tests/commands/candidate-audit-repair.test.ts +338 -0
- package/tests/commands/candidate-intake.test.ts +589 -0
- package/tests/commands/candidate-internalization-backfill.test.ts +480 -0
- package/tests/commands/candidate-internalize.test.ts +272 -0
- package/tests/commands/candidate-route.test.ts +328 -0
- package/tests/commands/candidate-show.test.ts +95 -0
- package/tests/commands/cli-command-tree.test.ts +64 -0
- package/tests/commands/context.test.ts +114 -0
- package/tests/commands/demo-story-a.test.ts +255 -0
- package/tests/commands/diagnose.test.ts +792 -0
- package/tests/commands/health.test.ts +330 -0
- package/tests/commands/pain-record.test.ts +316 -0
- package/tests/commands/plugin-config-resolution-cutover.test.ts +220 -0
- package/tests/commands/proven-channel-baseline.test.ts +441 -0
- package/tests/commands/runtime-activation.test.ts +168 -0
- package/tests/commands/runtime-canary.test.ts +369 -0
- package/tests/commands/runtime-diagnostics-export.test.ts +170 -0
- package/tests/commands/runtime-features.test.ts +114 -0
- package/tests/commands/runtime-health-snapshot.test.ts +357 -0
- package/tests/commands/runtime-internalization-enqueue-successors.test.ts +803 -0
- package/tests/commands/runtime-internalization-integrity-repair.test.ts +169 -0
- package/tests/commands/runtime-internalization-integrity.test.ts +102 -0
- package/tests/commands/runtime-internalization-queue.test.ts +252 -0
- package/tests/commands/runtime-internalization-run-once.test.ts +1318 -0
- package/tests/commands/runtime-internalization-wake-once.test.ts +170 -0
- package/tests/commands/runtime-internalization.test.ts +52 -0
- package/tests/commands/runtime-pain-flood-simulation.test.ts +418 -0
- package/tests/commands/runtime-pruning.test.ts +693 -0
- package/tests/commands/runtime-recovery.test.ts +96 -0
- package/tests/commands/runtime-synthetic-baseline.test.ts +249 -0
- package/tests/commands/runtime-uat.test.ts +397 -0
- package/tests/commands/runtime.test.ts +262 -0
- package/tests/commands/trace.test.ts +314 -0
- package/tests/e2e/candidate-intake-e2e.test.ts +316 -0
- package/tests/services/feature-flag-loader.test.ts +207 -0
- package/tests/services/proven-channel-baseline-runner.test.ts +30 -0
- package/tsconfig.json +26 -0
|
@@ -0,0 +1,479 @@
|
|
|
1
|
+
import * as path from 'path';
|
|
2
|
+
import {
|
|
3
|
+
RuntimeStateManager,
|
|
4
|
+
InternalizationOrchestrator,
|
|
5
|
+
isPeerRunnerKind,
|
|
6
|
+
hydratePITaskRecord,
|
|
7
|
+
} from '@principles/core/runtime-v2';
|
|
8
|
+
import type { CommitNextTaskResult } from '@principles/core/runtime-v2';
|
|
9
|
+
import { resolveWorkspaceDir } from '../resolve-workspace.js';
|
|
10
|
+
|
|
11
|
+
interface EnqueueSuccessorsOptions {
|
|
12
|
+
workspace?: string;
|
|
13
|
+
dryRun?: boolean;
|
|
14
|
+
confirm?: boolean;
|
|
15
|
+
json?: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
type EnqueueActionDecision =
|
|
19
|
+
| 'would_create_successor'
|
|
20
|
+
| 'successor_created'
|
|
21
|
+
| 'successor_exists'
|
|
22
|
+
| 'no_successor'
|
|
23
|
+
| 'skipped';
|
|
24
|
+
|
|
25
|
+
interface EnqueueAction {
|
|
26
|
+
taskId: string;
|
|
27
|
+
taskKind: string;
|
|
28
|
+
decision: EnqueueActionDecision;
|
|
29
|
+
successorKind?: string;
|
|
30
|
+
successorTaskId?: string;
|
|
31
|
+
reason?: string;
|
|
32
|
+
nextAction?: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
interface EnqueueSuccessorsOutput {
|
|
36
|
+
status: 'dry_run' | 'confirmed' | 'refused' | 'failed';
|
|
37
|
+
dryRun: boolean;
|
|
38
|
+
scannedCount: number;
|
|
39
|
+
createdCount: number;
|
|
40
|
+
existingCount: number;
|
|
41
|
+
skippedCount: number;
|
|
42
|
+
actions: EnqueueAction[];
|
|
43
|
+
error?: string;
|
|
44
|
+
reason?: string;
|
|
45
|
+
nextAction?: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const OWNER = 'pd-cli-enqueue-successors';
|
|
49
|
+
const RUNTIME_KIND = 'operator-repair';
|
|
50
|
+
|
|
51
|
+
function mapCommitDecisionToAction(
|
|
52
|
+
commitResult: CommitNextTaskResult,
|
|
53
|
+
): EnqueueAction {
|
|
54
|
+
switch (commitResult.decision) {
|
|
55
|
+
case 'successor_created':
|
|
56
|
+
return {
|
|
57
|
+
taskId: commitResult.sourceTaskId,
|
|
58
|
+
taskKind: '',
|
|
59
|
+
decision: 'successor_created',
|
|
60
|
+
successorKind: commitResult.successorKind,
|
|
61
|
+
successorTaskId: commitResult.successorTaskId,
|
|
62
|
+
};
|
|
63
|
+
case 'successor_exists':
|
|
64
|
+
return {
|
|
65
|
+
taskId: commitResult.sourceTaskId,
|
|
66
|
+
taskKind: '',
|
|
67
|
+
decision: 'successor_exists',
|
|
68
|
+
successorKind: commitResult.successorKind,
|
|
69
|
+
successorTaskId: commitResult.successorTaskId,
|
|
70
|
+
};
|
|
71
|
+
case 'no_successor':
|
|
72
|
+
return {
|
|
73
|
+
taskId: commitResult.sourceTaskId,
|
|
74
|
+
taskKind: '',
|
|
75
|
+
decision: 'no_successor',
|
|
76
|
+
reason: commitResult.reason,
|
|
77
|
+
};
|
|
78
|
+
case 'source_not_succeeded':
|
|
79
|
+
return {
|
|
80
|
+
taskId: commitResult.taskId,
|
|
81
|
+
taskKind: '',
|
|
82
|
+
decision: 'skipped',
|
|
83
|
+
reason: `source_not_succeeded: task status is ${commitResult.status}`,
|
|
84
|
+
nextAction: 'Re-run the task or investigate why status changed after scan',
|
|
85
|
+
};
|
|
86
|
+
case 'invalid_task_metadata':
|
|
87
|
+
return {
|
|
88
|
+
taskId: commitResult.taskId,
|
|
89
|
+
taskKind: '',
|
|
90
|
+
decision: 'skipped',
|
|
91
|
+
reason: `invalid_task_metadata: ${commitResult.reason}`,
|
|
92
|
+
nextAction: 'Inspect diagnosticJson and repair metadata via integrity-repair',
|
|
93
|
+
};
|
|
94
|
+
case 'task_not_found':
|
|
95
|
+
return {
|
|
96
|
+
taskId: commitResult.taskId,
|
|
97
|
+
taskKind: '',
|
|
98
|
+
decision: 'skipped',
|
|
99
|
+
reason: 'task_not_found: task disappeared between scan and commit',
|
|
100
|
+
nextAction: 'Re-scan or investigate concurrent deletion',
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function formatTextOutput(output: EnqueueSuccessorsOutput): string {
|
|
106
|
+
const lines: string[] = [];
|
|
107
|
+
const modeLabel = output.dryRun ? 'DRY-RUN' : 'CONFIRM';
|
|
108
|
+
|
|
109
|
+
lines.push('Internalization Enqueue Successors Report');
|
|
110
|
+
lines.push(`mode: ${modeLabel}`);
|
|
111
|
+
lines.push(`status: ${output.status}`);
|
|
112
|
+
lines.push('');
|
|
113
|
+
lines.push(`scanned: ${output.scannedCount}`);
|
|
114
|
+
lines.push(`created: ${output.createdCount}`);
|
|
115
|
+
lines.push(`existing: ${output.existingCount}`);
|
|
116
|
+
lines.push(`skipped: ${output.skippedCount}`);
|
|
117
|
+
lines.push('');
|
|
118
|
+
|
|
119
|
+
if (output.actions.length === 0) {
|
|
120
|
+
lines.push('No succeeded internalization tasks found. Nothing to enqueue.');
|
|
121
|
+
} else {
|
|
122
|
+
lines.push(`Actions (${output.actions.length}):`);
|
|
123
|
+
for (const action of output.actions) {
|
|
124
|
+
const icon = action.decision === 'successor_created' || action.decision === 'would_create_successor'
|
|
125
|
+
? '✓'
|
|
126
|
+
: action.decision === 'successor_exists'
|
|
127
|
+
? '≡'
|
|
128
|
+
: action.decision === 'no_successor'
|
|
129
|
+
? '○'
|
|
130
|
+
: '⚠';
|
|
131
|
+
lines.push(` ${icon} [${action.decision}] ${action.taskId} (${action.taskKind})`);
|
|
132
|
+
if (action.successorKind) {
|
|
133
|
+
lines.push(` successorKind: ${action.successorKind}`);
|
|
134
|
+
}
|
|
135
|
+
if (action.successorTaskId) {
|
|
136
|
+
lines.push(` successorTaskId: ${action.successorTaskId}`);
|
|
137
|
+
}
|
|
138
|
+
if (action.reason) {
|
|
139
|
+
lines.push(` reason: ${action.reason}`);
|
|
140
|
+
}
|
|
141
|
+
if (action.nextAction) {
|
|
142
|
+
lines.push(` nextAction: ${action.nextAction}`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return lines.join('\n');
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
interface EmitFailureOptions {
|
|
151
|
+
error: string;
|
|
152
|
+
isDryRun: boolean;
|
|
153
|
+
json: boolean;
|
|
154
|
+
reason?: string;
|
|
155
|
+
nextAction?: string;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function emitFailure(opts: EmitFailureOptions): void {
|
|
159
|
+
const failOutput: EnqueueSuccessorsOutput = {
|
|
160
|
+
status: 'failed',
|
|
161
|
+
dryRun: opts.isDryRun,
|
|
162
|
+
scannedCount: 0,
|
|
163
|
+
createdCount: 0,
|
|
164
|
+
existingCount: 0,
|
|
165
|
+
skippedCount: 0,
|
|
166
|
+
actions: [],
|
|
167
|
+
error: opts.error,
|
|
168
|
+
reason: opts.reason ?? opts.error,
|
|
169
|
+
nextAction: opts.nextAction ?? 'Check workspace path and storage availability, then re-run',
|
|
170
|
+
};
|
|
171
|
+
if (opts.json) {
|
|
172
|
+
console.log(JSON.stringify(failOutput, null, 2));
|
|
173
|
+
} else {
|
|
174
|
+
console.error(`Error: ${opts.error}`);
|
|
175
|
+
if (opts.nextAction) console.error(`Next action: ${opts.nextAction}`);
|
|
176
|
+
}
|
|
177
|
+
process.exitCode = 1;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
interface SuccessorIndexEntry {
|
|
181
|
+
taskId: string;
|
|
182
|
+
taskKind: string;
|
|
183
|
+
parentTaskId: string | null;
|
|
184
|
+
channel: string;
|
|
185
|
+
hydrated: boolean;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
async function buildSuccessorIndex(
|
|
189
|
+
stateManager: RuntimeStateManager,
|
|
190
|
+
): Promise<Map<string, SuccessorIndexEntry>> {
|
|
191
|
+
const allStatuses: ('pending' | 'retry_wait' | 'succeeded' | 'leased' | 'failed' | 'needs_human_review')[] = ['pending', 'retry_wait', 'succeeded', 'leased', 'failed', 'needs_human_review'];
|
|
192
|
+
const index = new Map<string, SuccessorIndexEntry>();
|
|
193
|
+
const results = await Promise.all(
|
|
194
|
+
allStatuses.map(status => stateManager.listTasks({ status })),
|
|
195
|
+
);
|
|
196
|
+
for (const task of results.flat()) {
|
|
197
|
+
if (!isPeerRunnerKind(task.taskKind)) continue;
|
|
198
|
+
const piTask = hydratePITaskRecord(task);
|
|
199
|
+
index.set(task.taskId, {
|
|
200
|
+
taskId: task.taskId,
|
|
201
|
+
taskKind: task.taskKind,
|
|
202
|
+
parentTaskId: piTask?.parentTaskId ?? null,
|
|
203
|
+
channel: piTask?.channel ?? '',
|
|
204
|
+
hydrated: piTask !== null,
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
return index;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function findSuccessorInIndex(
|
|
211
|
+
index: Map<string, SuccessorIndexEntry>,
|
|
212
|
+
opts: { parentTaskId: string; successorKind: string; channel: string; deterministicTaskId: string },
|
|
213
|
+
): { taskId: string; hydrated: boolean } | null {
|
|
214
|
+
const byTaskId = index.get(opts.deterministicTaskId);
|
|
215
|
+
if (byTaskId) {
|
|
216
|
+
return { taskId: byTaskId.taskId, hydrated: byTaskId.hydrated };
|
|
217
|
+
}
|
|
218
|
+
for (const entry of index.values()) {
|
|
219
|
+
if (entry.taskKind === opts.successorKind && entry.parentTaskId === opts.parentTaskId && entry.channel === opts.channel) {
|
|
220
|
+
return { taskId: entry.taskId, hydrated: entry.hydrated };
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export async function handleRuntimeInternalizationEnqueueSuccessors(opts: EnqueueSuccessorsOptions): Promise<void> {
|
|
227
|
+
const isDryRun = !opts.confirm;
|
|
228
|
+
|
|
229
|
+
const workspaceDirResult = await Promise.resolve().then(() =>
|
|
230
|
+
opts.workspace
|
|
231
|
+
? path.resolve(opts.workspace)
|
|
232
|
+
: resolveWorkspaceDir(),
|
|
233
|
+
).catch((resolveErr: unknown) => {
|
|
234
|
+
const message = resolveErr instanceof Error ? resolveErr.message : String(resolveErr);
|
|
235
|
+
emitFailure({
|
|
236
|
+
error: `Failed to resolve workspace: ${message}`,
|
|
237
|
+
isDryRun,
|
|
238
|
+
json: !!opts.json,
|
|
239
|
+
reason: `workspace_resolve_failed: ${message}`,
|
|
240
|
+
nextAction: 'Provide a valid --workspace path or ensure .principles directory exists',
|
|
241
|
+
});
|
|
242
|
+
return null;
|
|
243
|
+
});
|
|
244
|
+
if (workspaceDirResult === null) {
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
const workspaceDir = workspaceDirResult;
|
|
248
|
+
|
|
249
|
+
if (opts.dryRun && opts.confirm) {
|
|
250
|
+
if (opts.json) {
|
|
251
|
+
const conflictOutput: EnqueueSuccessorsOutput = {
|
|
252
|
+
status: 'refused',
|
|
253
|
+
dryRun: true,
|
|
254
|
+
scannedCount: 0,
|
|
255
|
+
createdCount: 0,
|
|
256
|
+
existingCount: 0,
|
|
257
|
+
skippedCount: 0,
|
|
258
|
+
actions: [],
|
|
259
|
+
error: '--dry-run and --confirm are mutually exclusive. Specify one or the other.',
|
|
260
|
+
reason: 'flag_conflict: --dry-run and --confirm are mutually exclusive',
|
|
261
|
+
nextAction: 'Specify either --dry-run or --confirm, not both',
|
|
262
|
+
};
|
|
263
|
+
console.log(JSON.stringify(conflictOutput, null, 2));
|
|
264
|
+
} else {
|
|
265
|
+
console.error('Error: --dry-run and --confirm are mutually exclusive. Specify one or the other.');
|
|
266
|
+
}
|
|
267
|
+
process.exitCode = 1;
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const stateManager = new RuntimeStateManager({ workspaceDir, readonly: isDryRun });
|
|
272
|
+
|
|
273
|
+
try {
|
|
274
|
+
try {
|
|
275
|
+
await stateManager.initialize();
|
|
276
|
+
} catch (initErr) {
|
|
277
|
+
const message = initErr instanceof Error ? initErr.message : String(initErr);
|
|
278
|
+
emitFailure({
|
|
279
|
+
error: `Failed to initialize storage: ${message}`,
|
|
280
|
+
isDryRun,
|
|
281
|
+
json: !!opts.json,
|
|
282
|
+
reason: `storage_init_failed: ${message}`,
|
|
283
|
+
nextAction: 'Check workspace path and .principles directory permissions',
|
|
284
|
+
});
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
const succeededTasks = await stateManager.listTasks({ status: 'succeeded' }).catch((listErr: unknown) => {
|
|
289
|
+
const message = listErr instanceof Error ? listErr.message : String(listErr);
|
|
290
|
+
emitFailure({
|
|
291
|
+
error: `Failed to list tasks: ${message}`,
|
|
292
|
+
isDryRun,
|
|
293
|
+
json: !!opts.json,
|
|
294
|
+
reason: `list_tasks_failed: ${message}`,
|
|
295
|
+
nextAction: 'Check database availability and re-run',
|
|
296
|
+
});
|
|
297
|
+
return null;
|
|
298
|
+
});
|
|
299
|
+
if (succeededTasks === null) {
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
const piSucceededTasks = succeededTasks.filter(t => isPeerRunnerKind(t.taskKind));
|
|
304
|
+
|
|
305
|
+
let successorIndex: Map<string, SuccessorIndexEntry> | null = null;
|
|
306
|
+
if (isDryRun) {
|
|
307
|
+
const index = await buildSuccessorIndex(stateManager).catch((indexErr: unknown) => {
|
|
308
|
+
const message = indexErr instanceof Error ? indexErr.message : String(indexErr);
|
|
309
|
+
emitFailure({
|
|
310
|
+
error: `Failed to build successor index: ${message}`,
|
|
311
|
+
isDryRun,
|
|
312
|
+
json: !!opts.json,
|
|
313
|
+
reason: `successor_index_failed: ${message}`,
|
|
314
|
+
nextAction: 'Check database availability and re-run',
|
|
315
|
+
});
|
|
316
|
+
return null;
|
|
317
|
+
});
|
|
318
|
+
if (index === null) {
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
successorIndex = index;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const orchestrator = new InternalizationOrchestrator(
|
|
325
|
+
{ stateManager },
|
|
326
|
+
{ owner: OWNER, runtimeKind: RUNTIME_KIND, dryRun: true },
|
|
327
|
+
);
|
|
328
|
+
|
|
329
|
+
const actions: EnqueueAction[] = [];
|
|
330
|
+
let createdCount = 0;
|
|
331
|
+
let existingCount = 0;
|
|
332
|
+
let skippedCount = 0;
|
|
333
|
+
|
|
334
|
+
for (const task of piSucceededTasks) {
|
|
335
|
+
const piTask = hydratePITaskRecord(task);
|
|
336
|
+
|
|
337
|
+
if (!piTask) {
|
|
338
|
+
actions.push({
|
|
339
|
+
taskId: task.taskId,
|
|
340
|
+
taskKind: task.taskKind,
|
|
341
|
+
decision: 'skipped',
|
|
342
|
+
reason: 'Failed to hydrate PITaskRecord from diagnosticJson',
|
|
343
|
+
nextAction: 'Inspect diagnosticJson and repair metadata via integrity-repair',
|
|
344
|
+
});
|
|
345
|
+
skippedCount++;
|
|
346
|
+
continue;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
if (isDryRun) {
|
|
350
|
+
const proposalResult = await orchestrator.proposeNextTask(task.taskId).catch((proposeErr: unknown) => {
|
|
351
|
+
const proposeMessage = proposeErr instanceof Error ? proposeErr.message : String(proposeErr);
|
|
352
|
+
return {
|
|
353
|
+
_proposeFailed: true as const,
|
|
354
|
+
reason: proposeMessage,
|
|
355
|
+
};
|
|
356
|
+
});
|
|
357
|
+
if (proposalResult !== null && '_proposeFailed' in proposalResult) {
|
|
358
|
+
actions.push({
|
|
359
|
+
taskId: task.taskId,
|
|
360
|
+
taskKind: piTask.taskKind,
|
|
361
|
+
decision: 'skipped',
|
|
362
|
+
reason: `propose_failed: ${proposalResult.reason}`,
|
|
363
|
+
nextAction: 'Re-run or investigate DB availability',
|
|
364
|
+
});
|
|
365
|
+
skippedCount++;
|
|
366
|
+
continue;
|
|
367
|
+
}
|
|
368
|
+
if (!proposalResult) {
|
|
369
|
+
actions.push({
|
|
370
|
+
taskId: task.taskId,
|
|
371
|
+
taskKind: piTask.taskKind,
|
|
372
|
+
decision: 'no_successor',
|
|
373
|
+
reason: 'No valid successor in job graph for this task kind and channel',
|
|
374
|
+
});
|
|
375
|
+
} else {
|
|
376
|
+
const deterministicTaskId = `${proposalResult.proposal.taskKind}-${task.taskId}-${proposalResult.proposal.channel}`;
|
|
377
|
+
if (!successorIndex) {
|
|
378
|
+
actions.push({
|
|
379
|
+
taskId: task.taskId,
|
|
380
|
+
taskKind: piTask.taskKind,
|
|
381
|
+
decision: 'skipped',
|
|
382
|
+
reason: 'successor_index_unavailable: index not built for dry-run path',
|
|
383
|
+
nextAction: 'Re-run the command',
|
|
384
|
+
});
|
|
385
|
+
skippedCount++;
|
|
386
|
+
continue;
|
|
387
|
+
}
|
|
388
|
+
const existingSuccessor = findSuccessorInIndex(
|
|
389
|
+
successorIndex,
|
|
390
|
+
{
|
|
391
|
+
parentTaskId: task.taskId,
|
|
392
|
+
successorKind: proposalResult.proposal.taskKind,
|
|
393
|
+
channel: proposalResult.proposal.channel,
|
|
394
|
+
deterministicTaskId,
|
|
395
|
+
},
|
|
396
|
+
);
|
|
397
|
+
if (existingSuccessor) {
|
|
398
|
+
if (!existingSuccessor.hydrated) {
|
|
399
|
+
actions.push({
|
|
400
|
+
taskId: task.taskId,
|
|
401
|
+
taskKind: piTask.taskKind,
|
|
402
|
+
decision: 'skipped',
|
|
403
|
+
reason: `successor_exists_with_malformed_metadata: taskId=${existingSuccessor.taskId} has unparseable diagnosticJson`,
|
|
404
|
+
nextAction: 'Run integrity-repair on the successor task, then re-run enqueue-successors',
|
|
405
|
+
});
|
|
406
|
+
skippedCount++;
|
|
407
|
+
} else {
|
|
408
|
+
actions.push({
|
|
409
|
+
taskId: task.taskId,
|
|
410
|
+
taskKind: piTask.taskKind,
|
|
411
|
+
decision: 'successor_exists',
|
|
412
|
+
successorKind: proposalResult.proposal.taskKind,
|
|
413
|
+
successorTaskId: existingSuccessor.taskId,
|
|
414
|
+
});
|
|
415
|
+
existingCount++;
|
|
416
|
+
}
|
|
417
|
+
} else {
|
|
418
|
+
actions.push({
|
|
419
|
+
taskId: task.taskId,
|
|
420
|
+
taskKind: piTask.taskKind,
|
|
421
|
+
decision: 'would_create_successor',
|
|
422
|
+
successorKind: proposalResult.proposal.taskKind,
|
|
423
|
+
});
|
|
424
|
+
createdCount++;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
} else {
|
|
428
|
+
const commitResult = await orchestrator.commitNextTaskProposal(task.taskId).catch((commitErr: unknown) => {
|
|
429
|
+
const commitMessage = commitErr instanceof Error ? commitErr.message : String(commitErr);
|
|
430
|
+
return {
|
|
431
|
+
decision: 'commit_failed' as const,
|
|
432
|
+
taskId: task.taskId,
|
|
433
|
+
reason: commitMessage,
|
|
434
|
+
};
|
|
435
|
+
});
|
|
436
|
+
if ('decision' in commitResult && commitResult.decision === 'commit_failed') {
|
|
437
|
+
actions.push({
|
|
438
|
+
taskId: task.taskId,
|
|
439
|
+
taskKind: piTask.taskKind,
|
|
440
|
+
decision: 'skipped',
|
|
441
|
+
reason: `commit_failed: ${commitResult.reason}`,
|
|
442
|
+
nextAction: 'Re-run or investigate DB availability',
|
|
443
|
+
});
|
|
444
|
+
skippedCount++;
|
|
445
|
+
continue;
|
|
446
|
+
}
|
|
447
|
+
const action = mapCommitDecisionToAction(commitResult);
|
|
448
|
+
action.taskKind = piTask.taskKind;
|
|
449
|
+
actions.push(action);
|
|
450
|
+
|
|
451
|
+
if (action.decision === 'successor_created') {
|
|
452
|
+
createdCount++;
|
|
453
|
+
} else if (action.decision === 'successor_exists') {
|
|
454
|
+
existingCount++;
|
|
455
|
+
} else if (action.decision === 'skipped') {
|
|
456
|
+
skippedCount++;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
const output: EnqueueSuccessorsOutput = {
|
|
462
|
+
status: isDryRun ? 'dry_run' : 'confirmed',
|
|
463
|
+
dryRun: isDryRun,
|
|
464
|
+
scannedCount: piSucceededTasks.length,
|
|
465
|
+
createdCount,
|
|
466
|
+
existingCount,
|
|
467
|
+
skippedCount,
|
|
468
|
+
actions,
|
|
469
|
+
};
|
|
470
|
+
|
|
471
|
+
if (opts.json) {
|
|
472
|
+
console.log(JSON.stringify(output, null, 2));
|
|
473
|
+
} else {
|
|
474
|
+
console.log(formatTextOutput(output));
|
|
475
|
+
}
|
|
476
|
+
} finally {
|
|
477
|
+
await stateManager.close();
|
|
478
|
+
}
|
|
479
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import * as path from 'path';
|
|
2
|
+
import { InternalizationIntegrityRemediation } from '@principles/core/runtime-v2';
|
|
3
|
+
import { resolveWorkspaceDir } from '../resolve-workspace.js';
|
|
4
|
+
import type { RemediationResult } from './remediation-output.js';
|
|
5
|
+
|
|
6
|
+
interface InternalizationIntegrityRepairOptions {
|
|
7
|
+
workspace?: string;
|
|
8
|
+
dryRun?: boolean;
|
|
9
|
+
confirm?: boolean;
|
|
10
|
+
json?: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function formatTextOutput(result: RemediationResult): string {
|
|
14
|
+
const lines: string[] = [];
|
|
15
|
+
|
|
16
|
+
lines.push('Internalization Integrity Repair Report');
|
|
17
|
+
lines.push(`generatedAt: ${result.generatedAt}`);
|
|
18
|
+
lines.push(`mode: ${result.mode === 'dry_run' ? 'DRY-RUN' : 'CONFIRM'}`);
|
|
19
|
+
lines.push(`status: ${result.status}`);
|
|
20
|
+
lines.push(`safeToConfirm: ${result.safeToConfirm}`);
|
|
21
|
+
lines.push(`repairedCount: ${result.repairedCount}`);
|
|
22
|
+
lines.push(`skippedCount: ${result.skippedCount}`);
|
|
23
|
+
lines.push('');
|
|
24
|
+
|
|
25
|
+
if (result.actions.length === 0) {
|
|
26
|
+
lines.push('No broken links found. Nothing to repair.');
|
|
27
|
+
} else {
|
|
28
|
+
lines.push(`Actions (${result.actions.length}):`);
|
|
29
|
+
for (const action of result.actions) {
|
|
30
|
+
const icon = action.severity === 'error' ? '✗' : '⚠';
|
|
31
|
+
lines.push(` ${icon} [${action.type ?? action.action}] ${action.taskId ?? action.targetId}`);
|
|
32
|
+
lines.push(` ${action.previousState ?? action.previousStatus ?? '(unknown)'} → ${action.nextState ?? action.newStatus ?? '(unknown)'}`);
|
|
33
|
+
lines.push(` action: ${action.action}`);
|
|
34
|
+
lines.push(` reason: ${action.reason}`);
|
|
35
|
+
if (action.successorTaskId) {
|
|
36
|
+
lines.push(` successorTaskId: ${action.successorTaskId}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return lines.join('\n');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export async function handleRuntimeInternalizationIntegrityRepair(opts: InternalizationIntegrityRepairOptions): Promise<void> {
|
|
45
|
+
const workspaceDir = opts.workspace
|
|
46
|
+
? path.resolve(opts.workspace)
|
|
47
|
+
: resolveWorkspaceDir();
|
|
48
|
+
|
|
49
|
+
if (opts.dryRun && opts.confirm) {
|
|
50
|
+
console.error('Error: --dry-run and --confirm are mutually exclusive. Specify one or the other.');
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const isDryRun = !opts.confirm;
|
|
55
|
+
|
|
56
|
+
const remediation = new InternalizationIntegrityRemediation({ workspaceDir });
|
|
57
|
+
const result = remediation.repair({ dryRun: isDryRun });
|
|
58
|
+
|
|
59
|
+
if (opts.json) {
|
|
60
|
+
console.log(JSON.stringify(result, null, 2));
|
|
61
|
+
} else {
|
|
62
|
+
console.log(formatTextOutput(result));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (!isDryRun && result.repairedCount === 0 && result.actions.length > 0) {
|
|
66
|
+
console.error('');
|
|
67
|
+
console.error('NOTE: No repairs were made. All issues were already resolved or skipped.');
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import * as path from 'path';
|
|
2
|
+
import { InternalizationChainIntegrityReadModel } from '@principles/core/runtime-v2';
|
|
3
|
+
import type { ChainIntegrityResult } from '@principles/core/runtime-v2';
|
|
4
|
+
import { resolveWorkspaceDir } from '../resolve-workspace.js';
|
|
5
|
+
|
|
6
|
+
interface InternalizationIntegrityOptions {
|
|
7
|
+
workspace?: string;
|
|
8
|
+
json?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function formatTextOutput(result: ChainIntegrityResult): string {
|
|
12
|
+
const lines: string[] = [];
|
|
13
|
+
const icon = result.overallStatus === 'ok' ? '✓' : result.overallStatus === 'degraded' ? '⚠' : '✗';
|
|
14
|
+
|
|
15
|
+
lines.push('Internalization Chain Integrity Report');
|
|
16
|
+
lines.push(`generatedAt: ${result.generatedAt}`);
|
|
17
|
+
lines.push(`OVERALL: ${icon} ${result.overallStatus.toUpperCase()}`);
|
|
18
|
+
lines.push('');
|
|
19
|
+
|
|
20
|
+
lines.push('Chain Summaries:');
|
|
21
|
+
lines.push(` totalCandidates: ${result.chainSummaries.totalCandidates}`);
|
|
22
|
+
lines.push(` totalDreamerTasks: ${result.chainSummaries.totalDreamerTasks}`);
|
|
23
|
+
lines.push(` totalPhilosopherTasks: ${result.chainSummaries.totalPhilosopherTasks}`);
|
|
24
|
+
lines.push(` totalPIArtifacts: ${result.chainSummaries.totalPIArtifacts}`);
|
|
25
|
+
lines.push(` chainsWithBrokenLinks: ${result.chainSummaries.chainsWithBrokenLinks}`);
|
|
26
|
+
lines.push('');
|
|
27
|
+
|
|
28
|
+
if (result.brokenLinks.length === 0) {
|
|
29
|
+
lines.push('No broken links found. Chain integrity is OK.');
|
|
30
|
+
} else {
|
|
31
|
+
lines.push(`Broken Links (${result.brokenLinks.length}):`);
|
|
32
|
+
for (const link of result.brokenLinks) {
|
|
33
|
+
const sevIcon = link.severity === 'error' ? '✗' : '⚠';
|
|
34
|
+
lines.push(` ${sevIcon} [${link.severity}] ${link.type}: ${link.reason}`);
|
|
35
|
+
if (link.taskId) lines.push(` taskId: ${link.taskId}`);
|
|
36
|
+
if (link.candidateId) lines.push(` candidateId: ${link.candidateId}`);
|
|
37
|
+
lines.push(` action: ${link.recommendedAction}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return lines.join('\n');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export async function handleRuntimeInternalizationIntegrity(opts: InternalizationIntegrityOptions): Promise<void> {
|
|
45
|
+
const workspaceDir = opts.workspace
|
|
46
|
+
? path.resolve(opts.workspace)
|
|
47
|
+
: resolveWorkspaceDir();
|
|
48
|
+
|
|
49
|
+
const model = new InternalizationChainIntegrityReadModel({ workspaceDir });
|
|
50
|
+
const result = model.check();
|
|
51
|
+
|
|
52
|
+
if (opts.json) {
|
|
53
|
+
console.log(JSON.stringify(result, null, 2));
|
|
54
|
+
} else {
|
|
55
|
+
console.log(formatTextOutput(result));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (result.overallStatus !== 'ok') {
|
|
59
|
+
console.error('');
|
|
60
|
+
console.error(`FAIL: overallStatus=${result.overallStatus}`);
|
|
61
|
+
process.exitCode = 1;
|
|
62
|
+
}
|
|
63
|
+
}
|