@principles/pd-cli 1.133.0 → 1.134.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.
Files changed (211) hide show
  1. package/dist/commands/__tests__/intent-flag-wiring.test.js +74 -3
  2. package/dist/commands/__tests__/intent-flag-wiring.test.js.map +1 -1
  3. package/dist/commands/__tests__/pain-retry-maxTokens-flag.test.d.ts +2 -0
  4. package/dist/commands/__tests__/pain-retry-maxTokens-flag.test.d.ts.map +1 -0
  5. package/dist/commands/__tests__/pain-retry-maxTokens-flag.test.js +60 -0
  6. package/dist/commands/__tests__/pain-retry-maxTokens-flag.test.js.map +1 -0
  7. package/dist/commands/__tests__/rulecode-flag-wiring.test.js +11 -4
  8. package/dist/commands/__tests__/rulecode-flag-wiring.test.js.map +1 -1
  9. package/dist/commands/__tests__/run-rulehost-flag-wiring.test.js +9 -0
  10. package/dist/commands/__tests__/run-rulehost-flag-wiring.test.js.map +1 -1
  11. package/dist/commands/admission-gate.d.ts +24 -0
  12. package/dist/commands/admission-gate.d.ts.map +1 -0
  13. package/dist/commands/admission-gate.js +29 -0
  14. package/dist/commands/admission-gate.js.map +1 -0
  15. package/dist/commands/candidate.d.ts.map +1 -1
  16. package/dist/commands/candidate.js +72 -6
  17. package/dist/commands/candidate.js.map +1 -1
  18. package/dist/commands/console.d.ts.map +1 -1
  19. package/dist/commands/console.js +40 -0
  20. package/dist/commands/console.js.map +1 -1
  21. package/dist/commands/demo-story-a.d.ts.map +1 -1
  22. package/dist/commands/demo-story-a.js +4 -2
  23. package/dist/commands/demo-story-a.js.map +1 -1
  24. package/dist/commands/diagnose.d.ts.map +1 -1
  25. package/dist/commands/diagnose.js +155 -8
  26. package/dist/commands/diagnose.js.map +1 -1
  27. package/dist/commands/errors-list.d.ts +25 -0
  28. package/dist/commands/errors-list.d.ts.map +1 -0
  29. package/dist/commands/errors-list.js +368 -0
  30. package/dist/commands/errors-list.js.map +1 -0
  31. package/dist/commands/health-codex.d.ts +7 -0
  32. package/dist/commands/health-codex.d.ts.map +1 -0
  33. package/dist/commands/health-codex.js +209 -0
  34. package/dist/commands/health-codex.js.map +1 -0
  35. package/dist/commands/health.d.ts +24 -0
  36. package/dist/commands/health.d.ts.map +1 -1
  37. package/dist/commands/health.js +48 -0
  38. package/dist/commands/health.js.map +1 -1
  39. package/dist/commands/intent.d.ts +21 -4
  40. package/dist/commands/intent.d.ts.map +1 -1
  41. package/dist/commands/intent.js +88 -27
  42. package/dist/commands/intent.js.map +1 -1
  43. package/dist/commands/pain-evidence.d.ts +6 -0
  44. package/dist/commands/pain-evidence.d.ts.map +1 -1
  45. package/dist/commands/pain-evidence.js +6 -0
  46. package/dist/commands/pain-evidence.js.map +1 -1
  47. package/dist/commands/pain-record.d.ts.map +1 -1
  48. package/dist/commands/pain-record.js +21 -0
  49. package/dist/commands/pain-record.js.map +1 -1
  50. package/dist/commands/pain-retry.d.ts +4 -0
  51. package/dist/commands/pain-retry.d.ts.map +1 -1
  52. package/dist/commands/pain-retry.js +327 -32
  53. package/dist/commands/pain-retry.js.map +1 -1
  54. package/dist/commands/proven-channel-baseline.d.ts.map +1 -1
  55. package/dist/commands/proven-channel-baseline.js +4 -2
  56. package/dist/commands/proven-channel-baseline.js.map +1 -1
  57. package/dist/commands/runtime-activation.d.ts +30 -0
  58. package/dist/commands/runtime-activation.d.ts.map +1 -1
  59. package/dist/commands/runtime-activation.js +567 -11
  60. package/dist/commands/runtime-activation.js.map +1 -1
  61. package/dist/commands/runtime-canary.d.ts.map +1 -1
  62. package/dist/commands/runtime-canary.js +32 -7
  63. package/dist/commands/runtime-canary.js.map +1 -1
  64. package/dist/commands/runtime-health-snapshot.d.ts.map +1 -1
  65. package/dist/commands/runtime-health-snapshot.js +4 -2
  66. package/dist/commands/runtime-health-snapshot.js.map +1 -1
  67. package/dist/commands/runtime-init.d.ts +43 -0
  68. package/dist/commands/runtime-init.d.ts.map +1 -0
  69. package/dist/commands/runtime-init.js +264 -0
  70. package/dist/commands/runtime-init.js.map +1 -0
  71. package/dist/commands/runtime-internalization-context-trace.d.ts +25 -0
  72. package/dist/commands/runtime-internalization-context-trace.d.ts.map +1 -0
  73. package/dist/commands/runtime-internalization-context-trace.js +374 -0
  74. package/dist/commands/runtime-internalization-context-trace.js.map +1 -0
  75. package/dist/commands/runtime-internalization-enqueue-successors.d.ts.map +1 -1
  76. package/dist/commands/runtime-internalization-enqueue-successors.js +3 -1
  77. package/dist/commands/runtime-internalization-enqueue-successors.js.map +1 -1
  78. package/dist/commands/runtime-internalization-integrity.d.ts.map +1 -1
  79. package/dist/commands/runtime-internalization-integrity.js +4 -2
  80. package/dist/commands/runtime-internalization-integrity.js.map +1 -1
  81. package/dist/commands/runtime-internalization-run-once.d.ts.map +1 -1
  82. package/dist/commands/runtime-internalization-run-once.js +20 -5
  83. package/dist/commands/runtime-internalization-run-once.js.map +1 -1
  84. package/dist/commands/runtime-internalization-run-rulehost.d.ts +1 -0
  85. package/dist/commands/runtime-internalization-run-rulehost.d.ts.map +1 -1
  86. package/dist/commands/runtime-internalization-run-rulehost.js +149 -6
  87. package/dist/commands/runtime-internalization-run-rulehost.js.map +1 -1
  88. package/dist/commands/runtime-uat.d.ts.map +1 -1
  89. package/dist/commands/runtime-uat.guard.test.js +13 -15
  90. package/dist/commands/runtime-uat.guard.test.js.map +1 -1
  91. package/dist/commands/runtime-uat.js +4 -3
  92. package/dist/commands/runtime-uat.js.map +1 -1
  93. package/dist/config-reader.js +1 -1
  94. package/dist/config-reader.js.map +1 -1
  95. package/dist/index.js +54 -78
  96. package/dist/index.js.map +1 -1
  97. package/dist/services/__tests__/evaluator-runner-deps.test.d.ts +2 -0
  98. package/dist/services/__tests__/evaluator-runner-deps.test.d.ts.map +1 -0
  99. package/dist/services/__tests__/evaluator-runner-deps.test.js +304 -0
  100. package/dist/services/__tests__/evaluator-runner-deps.test.js.map +1 -0
  101. package/dist/services/__tests__/rulehost-readiness.test.js.map +1 -1
  102. package/dist/services/__tests__/runtime-adapter-resolver.test.js.map +1 -1
  103. package/dist/services/config-doctor.d.ts.map +1 -1
  104. package/dist/services/config-doctor.js +9 -2
  105. package/dist/services/config-doctor.js.map +1 -1
  106. package/dist/services/pain-flood-simulation-runner.d.ts.map +1 -1
  107. package/dist/services/pain-flood-simulation-runner.js +9 -0
  108. package/dist/services/pain-flood-simulation-runner.js.map +1 -1
  109. package/dist/services/pd-config-loader.js +2 -2
  110. package/dist/services/pd-config-loader.js.map +1 -1
  111. package/dist/services/proven-channel-baseline-runner.d.ts.map +1 -1
  112. package/dist/services/proven-channel-baseline-runner.js +10 -2
  113. package/dist/services/proven-channel-baseline-runner.js.map +1 -1
  114. package/dist/services/quality-scorecard/data-extractor.js.map +1 -1
  115. package/dist/services/resolve-runtime-from-pd-config.js.map +1 -1
  116. package/dist/services/rulehost-pipeline-runner.d.ts +77 -1
  117. package/dist/services/rulehost-pipeline-runner.d.ts.map +1 -1
  118. package/dist/services/rulehost-pipeline-runner.js +111 -7
  119. package/dist/services/rulehost-pipeline-runner.js.map +1 -1
  120. package/dist/services/rulehost-readiness.js.map +1 -1
  121. package/dist/services/runtime-adapter-resolver.d.ts +1 -0
  122. package/dist/services/runtime-adapter-resolver.d.ts.map +1 -1
  123. package/dist/services/runtime-adapter-resolver.js +3 -0
  124. package/dist/services/runtime-adapter-resolver.js.map +1 -1
  125. package/dist/services/synthetic-baseline-runner.d.ts.map +1 -1
  126. package/dist/services/synthetic-baseline-runner.js +11 -0
  127. package/dist/services/synthetic-baseline-runner.js.map +1 -1
  128. package/dist/utils/production-workspace-guard.d.ts +4 -4
  129. package/dist/utils/production-workspace-guard.d.ts.map +1 -1
  130. package/dist/utils/production-workspace-guard.js +19 -16
  131. package/dist/utils/production-workspace-guard.js.map +1 -1
  132. package/dist/utils/production-workspace-guard.test.js +54 -19
  133. package/dist/utils/production-workspace-guard.test.js.map +1 -1
  134. package/package.json +8 -5
  135. package/src/commands/__tests__/intent-flag-wiring.test.ts +88 -3
  136. package/src/commands/__tests__/pain-retry-maxTokens-flag.test.ts +73 -0
  137. package/src/commands/__tests__/rulecode-flag-wiring.test.ts +31 -24
  138. package/src/commands/__tests__/run-rulehost-flag-wiring.test.ts +12 -0
  139. package/src/commands/admission-gate.ts +30 -0
  140. package/src/commands/candidate.ts +74 -6
  141. package/src/commands/console.ts +40 -0
  142. package/src/commands/demo-story-a.ts +4 -2
  143. package/src/commands/diagnose.ts +158 -10
  144. package/src/commands/errors-list.ts +440 -0
  145. package/src/commands/health-codex.ts +249 -0
  146. package/src/commands/health.ts +60 -0
  147. package/src/commands/intent.ts +98 -29
  148. package/src/commands/pain-evidence.ts +6 -0
  149. package/src/commands/pain-record.ts +21 -0
  150. package/src/commands/pain-retry.ts +353 -35
  151. package/src/commands/proven-channel-baseline.ts +4 -2
  152. package/src/commands/runtime-activation.ts +657 -12
  153. package/src/commands/runtime-canary.ts +31 -5
  154. package/src/commands/runtime-health-snapshot.ts +4 -2
  155. package/src/commands/runtime-init.ts +305 -0
  156. package/src/commands/runtime-internalization-context-trace.ts +445 -0
  157. package/src/commands/runtime-internalization-enqueue-successors.ts +3 -1
  158. package/src/commands/runtime-internalization-integrity.ts +4 -2
  159. package/src/commands/runtime-internalization-run-once.ts +20 -5
  160. package/src/commands/runtime-internalization-run-rulehost.ts +159 -6
  161. package/src/commands/runtime-uat.guard.test.ts +14 -16
  162. package/src/commands/runtime-uat.ts +4 -3
  163. package/src/config-reader.ts +1 -1
  164. package/src/index.ts +69 -78
  165. package/src/services/__tests__/evaluator-runner-deps.test.ts +341 -0
  166. package/src/services/config-doctor.ts +9 -2
  167. package/src/services/pain-flood-simulation-runner.ts +9 -0
  168. package/src/services/pd-config-loader.ts +2 -2
  169. package/src/services/proven-channel-baseline-runner.ts +10 -3
  170. package/src/services/rulehost-pipeline-runner.ts +157 -6
  171. package/src/services/runtime-adapter-resolver.ts +4 -0
  172. package/src/services/synthetic-baseline-runner.ts +11 -0
  173. package/src/utils/production-workspace-guard.test.ts +62 -20
  174. package/src/utils/production-workspace-guard.ts +19 -16
  175. package/tests/bdd/cli-contract.steps.ts +343 -0
  176. package/tests/bdd/context-trace.steps.ts +229 -0
  177. package/tests/bdd/support/gherkin-loader.ts +147 -0
  178. package/tests/bdd/support/repo-root.ts +62 -0
  179. package/tests/bdd/support/vitest-bdd.ts +179 -0
  180. package/tests/commands/admission-gate-coverage.test.ts +79 -0
  181. package/tests/commands/candidate-audit-repair.test.ts +77 -0
  182. package/tests/commands/candidate-intake.test.ts +155 -10
  183. package/tests/commands/candidate-internalization-backfill.test.ts +30 -0
  184. package/tests/commands/cli-help-snapshot.test.ts +15 -1
  185. package/tests/commands/console-open.test.ts +19 -0
  186. package/tests/commands/diagnose.test.ts +619 -14
  187. package/tests/commands/errors-list.test.ts +678 -0
  188. package/tests/commands/health-codex.test.ts +243 -0
  189. package/tests/commands/health-host-wiring.test.ts +76 -0
  190. package/tests/commands/intent.test.ts +4 -4
  191. package/tests/commands/pain-record.test.ts +80 -0
  192. package/tests/commands/pain-retry.test.ts +94 -3
  193. package/tests/commands/run-rulehost-handler.test.ts +133 -0
  194. package/tests/commands/runtime-activation-approve-flag-wiring.test.ts +227 -0
  195. package/tests/commands/runtime-activation-deactivate-flag-wiring.test.ts +167 -0
  196. package/tests/commands/runtime-activation-dispatch-flag-wiring.test.ts +262 -0
  197. package/tests/commands/runtime-activation-list-flag-wiring.test.ts +193 -0
  198. package/tests/commands/runtime-activation-promote-flag-wiring.test.ts +222 -0
  199. package/tests/commands/runtime-activation.test.ts +1090 -5
  200. package/tests/commands/runtime-canary.test.ts +50 -0
  201. package/tests/commands/runtime-features.test.ts +2 -0
  202. package/tests/commands/runtime-init-empty-workspace.test.ts +234 -0
  203. package/tests/commands/runtime-init.test.ts +346 -0
  204. package/tests/commands/runtime-internalization-context-trace.test.ts +110 -0
  205. package/tests/commands/runtime-internalization.test.ts +2 -2
  206. package/tests/config-reader.test.ts +6 -5
  207. package/tests/e2e/cross-package-acceptance.test.ts +55 -13
  208. package/tests/services/mainline-snapshot-assembler.test.ts +6 -3
  209. package/tests/services/resolve-runtime-from-pd-config.test.ts +2 -0
  210. package/tests/services/rulehost-pipeline-runner.test.ts +1 -1
  211. package/vitest.config.ts +1 -1
@@ -1,4 +1,5 @@
1
1
  import * as path from 'path';
2
+ import { createRequire } from 'module';
2
3
  import { OperatorHealthReadModel, SchemaConformanceReadModel, PruningReadModel, createInternalizationQueueReadModel, auditCandidateLedgerConsistency, buildGfiWorkspaceSnapshot, classifyGfiWorkspaceHealth } from '@principles/core/runtime-v2';
3
4
  import type { OperatorHealthSnapshot, SchemaConformanceResult, OrphanDetectionResult, InternalizationQueueSnapshot, GfiWorkspaceSnapshot, CandidateAuditResult } from '@principles/core/runtime-v2';
4
5
  import { resolveWorkspaceDir } from '../resolve-workspace.js';
@@ -20,6 +21,17 @@ export interface CanaryOutput {
20
21
  internalizationQueueSummary?: InternalizationQueueSummary;
21
22
  }
22
23
 
24
+ const require = createRequire(import.meta.url);
25
+
26
+ function readCliVersion(): string {
27
+ const packageMetadata: unknown = require('../../package.json');
28
+ if (typeof packageMetadata === 'object' && packageMetadata !== null && Object.hasOwn(packageMetadata, 'version')) {
29
+ const version: unknown = Reflect.get(packageMetadata, 'version');
30
+ if (typeof version === 'string') return version;
31
+ }
32
+ return 'unknown';
33
+ }
34
+
23
35
  export interface InternalizationQueueSummary {
24
36
  readyCount: number;
25
37
  retryWaitCount: number;
@@ -244,11 +256,23 @@ export async function runCanaryChecks(workspaceDir: string): Promise<CanaryOutpu
244
256
  const model = new OperatorHealthReadModel({ workspaceDir });
245
257
  try {
246
258
  const snapshot: OperatorHealthSnapshot = await model.getSnapshot();
247
- const status = snapshot.overallStatus === 'healthy' ? 'healthy' : snapshot.overallStatus === 'degraded' ? 'degraded' : 'error';
259
+ // Priority: real errors (e.g. DB missing) must surface as 'error' and not be
260
+ // masked by the cold-start `totalTaskCount === 0` branch, which is only a
261
+ // 'degraded' signal. Check overallStatus==='error' first, then unexercised,
262
+ // then healthy/degraded.
263
+ const status = snapshot.overallStatus === 'error'
264
+ ? 'error'
265
+ : snapshot.totalTaskCount === 0
266
+ ? 'degraded'
267
+ : snapshot.overallStatus === 'healthy' ? 'healthy' : 'degraded';
248
268
  return {
249
269
  name: 'runtime_health',
250
270
  status,
251
- summary: status === 'healthy'
271
+ summary: snapshot.overallStatus === 'error'
272
+ ? `Runtime health: ${snapshot.overallStatus}. Actions: ${snapshot.recommendedActions.join('; ')}`
273
+ : snapshot.totalTaskCount === 0
274
+ ? 'Runtime pipeline has not been exercised yet.'
275
+ : status === 'healthy'
252
276
  ? 'Runtime health OK.'
253
277
  : `Runtime health: ${snapshot.overallStatus}. Actions: ${snapshot.recommendedActions.join('; ')}`,
254
278
  details: snapshot,
@@ -272,7 +296,7 @@ export async function runCanaryChecks(workspaceDir: string): Promise<CanaryOutpu
272
296
  summary: status === 'healthy'
273
297
  ? `PD CLI accessible at ${cliPath}`
274
298
  : 'PD CLI entrypoint not found — verify installation.',
275
- details: { cliPath, exists: cliExists, version: '0.1.0' },
299
+ details: { cliPath, exists: cliExists, version: readCliVersion() },
276
300
  };
277
301
  } catch (err) {
278
302
  return { name: 'pd_shim_info', status: 'error', summary: 'PD shim check failed.', error: String(err) };
@@ -362,8 +386,10 @@ export async function handleRuntimeCanary(opts: CanaryOptions): Promise<void> {
362
386
  }
363
387
 
364
388
  if (output.overallStatus !== 'healthy') {
365
- console.error('');
366
- console.error(`FAIL: overallStatus=${output.overallStatus}`);
389
+ if (!opts.json) {
390
+ console.error('');
391
+ console.error(`FAIL: overallStatus=${output.overallStatus}`);
392
+ }
367
393
  process.exitCode = 1;
368
394
  }
369
395
  }
@@ -96,8 +96,10 @@ export async function handleRuntimeHealthSnapshot(opts: HealthSnapshotOptions):
96
96
  }
97
97
 
98
98
  if (snapshot.overallStatus !== 'healthy') {
99
- console.error('');
100
- console.error(`FAIL: overallStatus=${snapshot.overallStatus}`);
99
+ if (!opts.json) {
100
+ console.error('');
101
+ console.error(`FAIL: overallStatus=${snapshot.overallStatus}`);
102
+ }
101
103
  process.exitCode = 1;
102
104
  }
103
105
  } finally {
@@ -0,0 +1,305 @@
1
+ /**
2
+ * pd runtime init — Initialize all PD SQLite databases for a workspace.
3
+ *
4
+ * Creates state.db, trajectory.db, and subagent_workflows.db with full schema
5
+ * (tables + indexes + views + migrations). Idempotent: safe to run on existing
6
+ * workspaces (all CREATE statements use IF NOT EXISTS).
7
+ *
8
+ * Output contract (cli-1 strict-json, cli-4 dry-run/confirm mutex, cli-6 nextAction):
9
+ * - Default mode is --dry-run (no writes); use --confirm to actually initialize.
10
+ * - --json emits a single parseable JSON object on stdout.
11
+ * - Failures emit { ok: false, reason, nextAction } with exit code 1.
12
+ *
13
+ * ERR refs:
14
+ * - ERR-001/ERR-005: no `as` casts; DB rows typed via type guards
15
+ * - ERR-002: degraded paths include reason + nextAction
16
+ * - ERR-009/ERR-010: missing required fields fail loud
17
+ * - ERR-014: safe JSON.stringify on known output shapes
18
+ */
19
+
20
+ import * as path from 'path';
21
+ import { SqliteConnection } from '@principles/core/runtime-v2';
22
+ import { SchemaConformanceReadModel } from '@principles/core/runtime-v2';
23
+ import { initTrajectorySchema, initWorkflowSchema } from 'principles-disciple';
24
+ import { resolveWorkspaceDir } from '../resolve-workspace.js';
25
+ import { emitResult, emitFlagConflict, emitError } from '../services/cli-output.js';
26
+
27
+ // ── Output types ─────────────────────────────────────────────────────────────
28
+
29
+ export interface DatabaseInitResult {
30
+ name: string;
31
+ path: string;
32
+ tables: string[];
33
+ status: 'initialized' | 'verified' | 'skipped' | 'failed';
34
+ warnings: string[];
35
+ }
36
+
37
+ export interface RuntimeInitOutput {
38
+ ok: boolean;
39
+ mode: 'dry-run' | 'confirm';
40
+ workspace: string;
41
+ databases: DatabaseInitResult[];
42
+ warnings: string[];
43
+ reason?: string;
44
+ nextAction?: string;
45
+ }
46
+
47
+ // ── Build output ─────────────────────────────────────────────────────────────
48
+
49
+ const DB_NAMES = {
50
+ state: 'state.db',
51
+ trajectory: 'trajectory.db',
52
+ workflow: 'subagent_workflows.db',
53
+ } as const;
54
+
55
+ export function buildRuntimeInitOutput(workspaceDir: string, confirm: boolean): RuntimeInitOutput {
56
+ const resolvedWorkspace = path.resolve(workspaceDir);
57
+ const warnings: string[] = [];
58
+ const databases: DatabaseInitResult[] = [];
59
+
60
+ // 1. state.db (via SqliteConnection, which triggers initSchema + migrateSchema)
61
+ const stateDbPath = path.join(resolvedWorkspace, '.pd', 'state.db');
62
+ if (!confirm) {
63
+ // dry-run: report what would be initialized without touching disk
64
+ databases.push({
65
+ name: DB_NAMES.state,
66
+ path: stateDbPath,
67
+ tables: ['tasks', 'runs', 'artifacts', 'commits', 'principle_candidates',
68
+ 'pi_artifacts', 'approvals', 'activations', 'intent_decisions', 'schema_version'],
69
+ status: 'skipped',
70
+ warnings: [],
71
+ });
72
+ } else {
73
+ try {
74
+ const conn = new SqliteConnection({ workspaceDir: resolvedWorkspace, readonly: false });
75
+ try {
76
+ conn.getDb(); // triggers initSchema + migrateSchema
77
+ const connWarnings = conn.getSchemaInitWarnings();
78
+ if (connWarnings.length > 0) {
79
+ warnings.push(...connWarnings.map(w => `${DB_NAMES.state}: ${w}`));
80
+ }
81
+ databases.push({
82
+ name: DB_NAMES.state,
83
+ path: stateDbPath,
84
+ tables: ['tasks', 'runs', 'artifacts', 'commits', 'principle_candidates',
85
+ 'pi_artifacts', 'approvals', 'activations', 'intent_decisions', 'schema_version'],
86
+ status: 'initialized',
87
+ warnings: connWarnings,
88
+ });
89
+ } finally {
90
+ conn.close();
91
+ }
92
+ } catch (err) {
93
+ const reason = err instanceof Error ? err.message : String(err);
94
+ databases.push({
95
+ name: DB_NAMES.state,
96
+ path: stateDbPath,
97
+ tables: [],
98
+ status: 'failed',
99
+ warnings: [reason],
100
+ });
101
+ return {
102
+ ok: false,
103
+ mode: 'confirm',
104
+ workspace: resolvedWorkspace,
105
+ databases,
106
+ warnings,
107
+ reason: `state.db initialization failed: ${reason}`,
108
+ nextAction: 'Check workspace directory permissions and disk space, then retry.',
109
+ };
110
+ }
111
+ }
112
+
113
+ // 2. trajectory.db (via initTrajectorySchema)
114
+ if (!confirm) {
115
+ databases.push({
116
+ name: DB_NAMES.trajectory,
117
+ path: path.join(resolvedWorkspace, '.state', 'trajectory.db'),
118
+ tables: ['schema_version', 'ingest_checkpoint', 'sessions', 'assistant_turns',
119
+ 'user_turns', 'tool_calls', 'pain_events', 'gate_blocks', 'trust_changes',
120
+ 'principle_events', 'task_outcomes', 'correction_samples', 'sample_reviews',
121
+ 'exports_audit', 'evolution_tasks', 'evolution_events'],
122
+ status: 'skipped',
123
+ warnings: [],
124
+ });
125
+ } else {
126
+ try {
127
+ const result = initTrajectorySchema(resolvedWorkspace);
128
+ if (result.warnings.length > 0) {
129
+ warnings.push(...result.warnings.map((w: string) => `${DB_NAMES.trajectory}: ${w}`));
130
+ }
131
+ databases.push({
132
+ name: DB_NAMES.trajectory,
133
+ path: path.join(resolvedWorkspace, '.state', 'trajectory.db'),
134
+ tables: result.tables,
135
+ status: 'initialized',
136
+ warnings: result.warnings,
137
+ });
138
+ } catch (err) {
139
+ const reason = err instanceof Error ? err.message : String(err);
140
+ databases.push({
141
+ name: DB_NAMES.trajectory,
142
+ path: path.join(resolvedWorkspace, '.state', 'trajectory.db'),
143
+ tables: [],
144
+ status: 'failed',
145
+ warnings: [reason],
146
+ });
147
+ return {
148
+ ok: false,
149
+ mode: 'confirm',
150
+ workspace: resolvedWorkspace,
151
+ databases,
152
+ warnings,
153
+ reason: `trajectory.db initialization failed: ${reason}`,
154
+ nextAction: 'Check workspace directory permissions and disk space, then retry.',
155
+ };
156
+ }
157
+ }
158
+
159
+ // 3. subagent_workflows.db (via initWorkflowSchema)
160
+ if (!confirm) {
161
+ databases.push({
162
+ name: DB_NAMES.workflow,
163
+ path: path.join(resolvedWorkspace, '.state', 'subagent_workflows.db'),
164
+ tables: ['schema_version', 'subagent_workflows', 'subagent_workflow_events'],
165
+ status: 'skipped',
166
+ warnings: [],
167
+ });
168
+ } else {
169
+ try {
170
+ const result = initWorkflowSchema(resolvedWorkspace);
171
+ if (result.warnings.length > 0) {
172
+ warnings.push(...result.warnings.map((w: string) => `${DB_NAMES.workflow}: ${w}`));
173
+ }
174
+ databases.push({
175
+ name: DB_NAMES.workflow,
176
+ path: path.join(resolvedWorkspace, '.state', 'subagent_workflows.db'),
177
+ tables: result.tables,
178
+ status: 'initialized',
179
+ warnings: result.warnings,
180
+ });
181
+ } catch (err) {
182
+ const reason = err instanceof Error ? err.message : String(err);
183
+ databases.push({
184
+ name: DB_NAMES.workflow,
185
+ path: path.join(resolvedWorkspace, '.state', 'subagent_workflows.db'),
186
+ tables: [],
187
+ status: 'failed',
188
+ warnings: [reason],
189
+ });
190
+ return {
191
+ ok: false,
192
+ mode: 'confirm',
193
+ workspace: resolvedWorkspace,
194
+ databases,
195
+ warnings,
196
+ reason: `subagent_workflows.db initialization failed: ${reason}`,
197
+ nextAction: 'Check workspace directory permissions and disk space, then retry.',
198
+ };
199
+ }
200
+ }
201
+
202
+ // Verify state.db schema conformance after initialization (confirm mode only)
203
+ if (confirm) {
204
+ try {
205
+ const conformance = new SchemaConformanceReadModel({ workspaceDir: resolvedWorkspace });
206
+ const result = conformance.check();
207
+ if (result.overallStatus === 'error') {
208
+ warnings.push(`state.db schema conformance check returned 'error' — some tables or indexes may be missing`);
209
+ }
210
+ } catch (err) {
211
+ // Non-fatal: schema conformance check is a post-verification step
212
+ warnings.push(`schema conformance verification skipped: ${err instanceof Error ? err.message : String(err)}`);
213
+ }
214
+ }
215
+
216
+ return {
217
+ ok: true,
218
+ mode: confirm ? 'confirm' : 'dry-run',
219
+ workspace: resolvedWorkspace,
220
+ databases,
221
+ warnings,
222
+ };
223
+ }
224
+
225
+ // ── Text formatting ──────────────────────────────────────────────────────────
226
+
227
+ function formatTextOutput(output: RuntimeInitOutput): string {
228
+ const lines: string[] = [];
229
+
230
+ lines.push('PD Runtime Init');
231
+ lines.push(`mode: ${output.mode}`);
232
+ lines.push(`workspace: ${output.workspace}`);
233
+ lines.push('');
234
+
235
+ for (const db of output.databases) {
236
+ const icon = db.status === 'initialized' ? '[+]' :
237
+ db.status === 'verified' ? '[v]' :
238
+ db.status === 'skipped' ? '[ ]' : '[x]';
239
+ lines.push(`${icon} ${db.name} (${db.status})`);
240
+ lines.push(` path: ${db.path}`);
241
+ if (db.tables.length > 0) {
242
+ lines.push(` tables: ${db.tables.length} (${db.tables.slice(0, 5).join(', ')}${db.tables.length > 5 ? ', ...' : ''})`);
243
+ }
244
+ for (const w of db.warnings) {
245
+ lines.push(` warning: ${w}`);
246
+ }
247
+ }
248
+
249
+ if (output.warnings.length > 0) {
250
+ lines.push('');
251
+ lines.push('Warnings:');
252
+ for (const w of output.warnings) {
253
+ lines.push(` [!] ${w}`);
254
+ }
255
+ }
256
+
257
+ if (!output.ok && output.reason) {
258
+ lines.push('');
259
+ lines.push(`Error: ${output.reason}`);
260
+ if (output.nextAction) {
261
+ lines.push(`→ ${output.nextAction}`);
262
+ }
263
+ }
264
+
265
+ return lines.join('\n');
266
+ }
267
+
268
+ // ── CLI handler ──────────────────────────────────────────────────────────────
269
+
270
+ export interface RuntimeInitOptions {
271
+ workspace?: string;
272
+ dryRun?: boolean;
273
+ confirm?: boolean;
274
+ json?: boolean;
275
+ }
276
+
277
+ export async function handleRuntimeInit(opts: RuntimeInitOptions): Promise<void> {
278
+ // cli-4: --dry-run and --confirm are mutually exclusive
279
+ if (opts.dryRun && opts.confirm) {
280
+ process.exitCode = emitFlagConflict({ json: opts.json ?? false });
281
+ return;
282
+ }
283
+
284
+ const workspaceDir = opts.workspace
285
+ ? path.resolve(opts.workspace)
286
+ : resolveWorkspaceDir();
287
+
288
+ // Default is dry-run; --confirm opts in to actual initialization
289
+ const confirm = opts.confirm === true;
290
+
291
+ try {
292
+ const output = buildRuntimeInitOutput(workspaceDir, confirm);
293
+ emitResult(output, { json: opts.json ?? false, formatText: formatTextOutput });
294
+
295
+ if (!output.ok) {
296
+ process.exitCode = 1; // cli-2: set exit code, no process.exit()
297
+ }
298
+ } catch (err) {
299
+ process.exitCode = emitError(err, {
300
+ json: opts.json ?? false,
301
+ nextAction: 'Check workspace directory and permissions, then retry.',
302
+ });
303
+ }
304
+ }
305
+