@principles/pd-cli 1.145.2 → 1.146.1

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 CHANGED
@@ -15,13 +15,22 @@ npm install -g @principles/pd-cli
15
15
  Record a pain signal to the workspace's trajectory database via `PainToPrincipleService`.
16
16
 
17
17
  ```bash
18
- pd pain record --reason "edited file without reading first" --score 75
18
+ pd pain record --reason "edited file without reading first" --score 75 --session "<session-id>"
19
19
  ```
20
20
 
21
21
  Options:
22
22
  - `--reason, -r` — Pain reason (required)
23
23
  - `--score, -s` — Pain score 0-100 (default: 80)
24
- - `--session-id` — Session ID (default: auto-generated)
24
+ - `--session` — Session ID recorded in this workspace's trajectory; validated
25
+ up front (a missing session fails with `session_not_found` before anything
26
+ is written). Binding a session attaches real trajectory evidence.
27
+ - `--workspace, -w` — Workspace directory
28
+ - `--wait` — Diagnose synchronously (overrides the async CLI flag)
29
+ - `--json` — Machine-readable output
30
+
31
+ Without `--session` the record is an honest unbound Owner report: it carries
32
+ no trajectory evidence and candidates will likely be gated by the admission
33
+ threshold (`needs_evidence`); the output discloses this explicitly.
25
34
 
26
35
  ## Production Canary Validation
27
36
 
@@ -10,12 +10,31 @@
10
10
  */
11
11
  import type { PainEvidenceEntry } from '@principles/core/runtime-v2';
12
12
  /**
13
- * Build trajectory evidence entries by reading trajectory.db directly.
13
+ * PRI-642 (SPEC §7.3): discriminated acquisition result. `unavailable` carries
14
+ * a distinct reasonCode so `pd pain record --session` can fail/degrade
15
+ * explicitly BEFORE any LLM/task/candidate mutation, without placeholder
16
+ * evidence.
17
+ */
18
+ export type TrajectoryEvidenceAcquisition = {
19
+ status: 'available';
20
+ entries: PainEvidenceEntry[];
21
+ } | {
22
+ status: 'unavailable';
23
+ reasonCode: 'trajectory_unavailable' | 'session_not_found' | 'empty_trajectory' | 'evidence_read_failed';
24
+ detail: string;
25
+ };
26
+ /**
27
+ * PRI-642 Scope A typed acquisition from trajectory.db (SPEC §7.3).
14
28
  *
15
- * @param stateDir - The .state directory containing trajectory.db
16
- * @param sessionId - The session ID to query turns for
17
- * @param workspaceDir - Workspace directory for path redaction (sanitizeString)
18
- * @returns Array of PainEvidenceEntry (never empty; degraded entries on failure)
29
+ * Validates that the requested session exists in the trajectory `sessions`
30
+ * table (every recorded turn/tool call upserts its session row, so an absent
31
+ * row means the session was never seen) and classifies the outcome:
32
+ * - `available` — session bound, ≥1 real behavior-trace entry;
33
+ * - `session_not_found` — session absent from the sessions table (or a
34
+ * `cli`/`unknown` sentinel — never a real session);
35
+ * - `trajectory_unavailable` — no trajectory.db in this workspace;
36
+ * - `evidence_read_failed` — the DB exists but cannot be opened/read;
37
+ * - `empty_trajectory` — real session, no usable evidence rows.
19
38
  */
20
- export declare function buildTrajectoryEvidenceFromDb(stateDir: string, sessionId: string | undefined, workspaceDir?: string): PainEvidenceEntry[];
39
+ export declare function acquireTrajectoryEvidenceFromDb(stateDir: string, sessionId: string | undefined, workspaceDir?: string): TrajectoryEvidenceAcquisition;
21
40
  //# sourceMappingURL=build-trajectory-evidence.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"build-trajectory-evidence.d.ts","sourceRoot":"","sources":["../../src/commands/build-trajectory-evidence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAUH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAErE;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,YAAY,CAAC,EAAE,MAAM,GACpB,iBAAiB,EAAE,CAyJrB"}
1
+ {"version":3,"file":"build-trajectory-evidence.d.ts","sourceRoot":"","sources":["../../src/commands/build-trajectory-evidence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAUH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAErE;;;;;GAKG;AACH,MAAM,MAAM,6BAA6B,GACrC;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,iBAAiB,EAAE,CAAA;CAAE,GACrD;IACE,MAAM,EAAE,aAAa,CAAC;IACtB,UAAU,EAAE,wBAAwB,GAAG,mBAAmB,GAAG,kBAAkB,GAAG,sBAAsB,CAAC;IACzG,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AA6JN;;;;;;;;;;;;GAYG;AACH,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,YAAY,CAAC,EAAE,MAAM,GACpB,6BAA6B,CAoE/B"}
@@ -12,110 +12,90 @@ import Database from 'better-sqlite3';
12
12
  import * as fs from 'fs';
13
13
  import * as path from 'path';
14
14
  import { MAX_EVIDENCE_ENTRIES, MAX_EVIDENCE_NOTE_CHARS, sanitizeString, } from '@principles/core/runtime-v2';
15
+ /** SourceRef markers that carry no real behavior trace (placeholder shapes). */
16
+ const PLACEHOLDER_SOURCE_REFS = new Set([
17
+ 'owner_reported:cli',
18
+ 'owner_message:unavailable',
19
+ 'agent_turn:unavailable',
20
+ 'tool_call_failure:unavailable',
21
+ 'trajectory:empty',
22
+ ]);
15
23
  /**
16
- * Build trajectory evidence entries by reading trajectory.db directly.
17
- *
18
- * @param stateDir - The .state directory containing trajectory.db
19
- * @param sessionId - The session ID to query turns for
20
- * @param workspaceDir - Workspace directory for path redaction (sanitizeString)
21
- * @returns Array of PainEvidenceEntry (never empty; degraded entries on failure)
24
+ * Collect evidence entries from an open trajectory.db for one session.
25
+ * Shared by the typed acquisition API and the legacy array wrapper so the
26
+ * two can never drift.
22
27
  */
23
- export function buildTrajectoryEvidenceFromDb(stateDir, sessionId, workspaceDir) {
28
+ function collectEvidenceFromDb(db, sessionId, workspaceDir) {
24
29
  const evidence = [];
25
- // No session or empty → placeholder entry (ERR-002: never return empty array silently)
26
- if (!sessionId || sessionId === 'cli' || sessionId === 'unknown') {
27
- evidence.push({
28
- sourceRef: 'owner_reported:cli',
29
- note: 'No session context available',
30
- });
31
- return evidence;
32
- }
33
- const dbPath = path.join(stateDir, 'trajectory.db');
34
- if (!fs.existsSync(dbPath)) {
35
- evidence.push({
36
- sourceRef: 'owner_reported:cli',
37
- note: 'No session context available',
38
- });
39
- return evidence;
40
- }
41
- let db;
42
- try {
43
- db = new Database(dbPath, { readonly: true });
44
- }
45
- catch {
46
- evidence.push({
47
- sourceRef: 'owner_reported:cli',
48
- note: 'No session context available',
49
- });
50
- return evidence;
51
- }
30
+ let readFailed = false;
31
+ // Try to read user turns with correction detection
52
32
  try {
53
- // Try to read user turns with correction detection
54
- try {
55
- const userTurns = db.prepare(`
33
+ const userTurns = db.prepare(`
56
34
  SELECT id, raw_excerpt, correction_detected, correction_cue, created_at
57
35
  FROM user_turns
58
36
  WHERE session_id = ?
59
37
  ORDER BY id ASC
60
38
  `).all(sessionId);
61
- const lastCorrectionTurn = [...userTurns].reverse().find(t => Boolean(t.correction_detected));
62
- if (lastCorrectionTurn) {
63
- const rawExcerpt = typeof lastCorrectionTurn.raw_excerpt === 'string'
64
- ? lastCorrectionTurn.raw_excerpt
65
- : '';
66
- const sanitizedNote = sanitizeString(rawExcerpt.slice(0, MAX_EVIDENCE_NOTE_CHARS), workspaceDir);
67
- evidence.push({
68
- sourceRef: `owner_message:${String(lastCorrectionTurn.created_at ?? 'unknown')}`,
69
- note: sanitizedNote,
70
- });
71
- }
39
+ const lastCorrectionTurn = [...userTurns].reverse().find(t => Boolean(t.correction_detected));
40
+ if (lastCorrectionTurn) {
41
+ const rawExcerpt = typeof lastCorrectionTurn.raw_excerpt === 'string'
42
+ ? lastCorrectionTurn.raw_excerpt
43
+ : '';
44
+ const sanitizedNote = sanitizeString(rawExcerpt.slice(0, MAX_EVIDENCE_NOTE_CHARS), workspaceDir);
45
+ evidence.push({
46
+ sourceRef: `owner_message:${String(lastCorrectionTurn.created_at ?? 'unknown')}`,
47
+ note: sanitizedNote,
48
+ });
72
49
  }
73
- catch {
74
- // user_turns table may not exist — degrade gracefully
75
- if (evidence.length < MAX_EVIDENCE_ENTRIES) {
76
- evidence.push({
77
- sourceRef: 'owner_message:unavailable',
78
- note: 'trajectory_user_turns_unavailable',
79
- });
80
- }
50
+ }
51
+ catch {
52
+ readFailed = true;
53
+ // user_turns table may not exist — degrade gracefully
54
+ if (evidence.length < MAX_EVIDENCE_ENTRIES) {
55
+ evidence.push({
56
+ sourceRef: 'owner_message:unavailable',
57
+ note: 'trajectory_user_turns_unavailable',
58
+ });
81
59
  }
82
- // Try to read assistant turns (last 3)
83
- try {
84
- const assistantTurns = db.prepare(`
60
+ }
61
+ // Try to read assistant turns (last 3)
62
+ try {
63
+ const assistantTurns = db.prepare(`
85
64
  SELECT id, sanitized_text, stop_reason, created_at
86
65
  FROM assistant_turns
87
66
  WHERE session_id = ?
88
67
  ORDER BY id ASC
89
68
  `).all(sessionId);
90
- const recentAssistant = assistantTurns.slice(-3);
91
- for (const turn of recentAssistant) {
92
- if (evidence.length >= MAX_EVIDENCE_ENTRIES)
93
- break;
94
- const sanitizedText = typeof turn.sanitized_text === 'string'
95
- ? turn.sanitized_text
96
- : '';
97
- const sanitizedNote = sanitizeString(sanitizedText.slice(0, MAX_EVIDENCE_NOTE_CHARS), workspaceDir);
98
- // Enhanced: append truncation warning when stop_reason=length
99
- const stopReason = typeof turn.stop_reason === 'string' ? turn.stop_reason : null;
100
- const truncationWarning = stopReason === 'length' ? ' [TRUNCATED: output cut off by length limit]' : '';
101
- evidence.push({
102
- sourceRef: `agent_turn:${String(turn.created_at ?? 'unknown')}`,
103
- note: sanitizedNote + truncationWarning,
104
- });
105
- }
69
+ const recentAssistant = assistantTurns.slice(-3);
70
+ for (const turn of recentAssistant) {
71
+ if (evidence.length >= MAX_EVIDENCE_ENTRIES)
72
+ break;
73
+ const sanitizedText = typeof turn.sanitized_text === 'string'
74
+ ? turn.sanitized_text
75
+ : '';
76
+ const sanitizedNote = sanitizeString(sanitizedText.slice(0, MAX_EVIDENCE_NOTE_CHARS), workspaceDir);
77
+ // Enhanced: append truncation warning when stop_reason=length
78
+ const stopReason = typeof turn.stop_reason === 'string' ? turn.stop_reason : null;
79
+ const truncationWarning = stopReason === 'length' ? ' [TRUNCATED: output cut off by length limit]' : '';
80
+ evidence.push({
81
+ sourceRef: `agent_turn:${String(turn.created_at ?? 'unknown')}`,
82
+ note: sanitizedNote + truncationWarning,
83
+ });
106
84
  }
107
- catch {
108
- // assistant_turns table may not exist — degrade gracefully
109
- if (evidence.length < MAX_EVIDENCE_ENTRIES) {
110
- evidence.push({
111
- sourceRef: 'agent_turn:unavailable',
112
- note: 'trajectory_assistant_turns_unavailable',
113
- });
114
- }
85
+ }
86
+ catch {
87
+ readFailed = true;
88
+ // assistant_turns table may not exist — degrade gracefully
89
+ if (evidence.length < MAX_EVIDENCE_ENTRIES) {
90
+ evidence.push({
91
+ sourceRef: 'agent_turn:unavailable',
92
+ note: 'trajectory_assistant_turns_unavailable',
93
+ });
115
94
  }
116
- // PRI-358: Try to read failed tool_calls (last 3 failures, chronological order)
117
- try {
118
- const failedToolCalls = db.prepare(`
95
+ }
96
+ // PRI-358: Try to read failed tool_calls (last 3 failures, chronological order)
97
+ try {
98
+ const failedToolCalls = db.prepare(`
119
99
  SELECT tool_name, error_type, exit_code, result_preview, created_at
120
100
  FROM (
121
101
  SELECT tool_name, error_type, exit_code, result_preview, created_at
@@ -126,39 +106,119 @@ export function buildTrajectoryEvidenceFromDb(stateDir, sessionId, workspaceDir)
126
106
  )
127
107
  ORDER BY created_at ASC
128
108
  `).all(sessionId);
129
- for (const tc of failedToolCalls) {
130
- if (evidence.length >= MAX_EVIDENCE_ENTRIES)
131
- break;
132
- const toolName = typeof tc.tool_name === 'string' ? tc.tool_name : 'unknown';
133
- const errorType = typeof tc.error_type === 'string' ? tc.error_type : 'unknown';
134
- const exitCode = tc.exit_code != null ? String(tc.exit_code) : 'N/A';
135
- // Enhanced: append resultPreview when available
136
- const resultPreview = typeof tc.result_preview === 'string' ? tc.result_preview : null;
137
- const previewSuffix = resultPreview ? ` | ${resultPreview.slice(0, 200)}` : '';
138
- const note = `Tool ${toolName} failed: ${errorType} (exitCode: ${exitCode})${previewSuffix}`;
139
- evidence.push({
140
- sourceRef: `tool_call_failure:${String(tc.created_at ?? 'unknown')}`,
141
- note: sanitizeString(note.slice(0, MAX_EVIDENCE_NOTE_CHARS), workspaceDir),
142
- });
143
- }
144
- }
145
- catch {
146
- // tool_calls table may not exist — degrade gracefully (only when no other evidence)
147
- if (evidence.length === 0) {
148
- evidence.push({
149
- sourceRef: 'tool_call_failure:unavailable',
150
- note: 'trajectory_tool_calls_unavailable',
151
- });
152
- }
109
+ for (const tc of failedToolCalls) {
110
+ if (evidence.length >= MAX_EVIDENCE_ENTRIES)
111
+ break;
112
+ const toolName = typeof tc.tool_name === 'string' ? tc.tool_name : 'unknown';
113
+ const errorType = typeof tc.error_type === 'string' ? tc.error_type : 'unknown';
114
+ const exitCode = tc.exit_code != null ? String(tc.exit_code) : 'N/A';
115
+ // Enhanced: append resultPreview when available
116
+ const resultPreview = typeof tc.result_preview === 'string' ? tc.result_preview : null;
117
+ const previewSuffix = resultPreview ? ` | ${resultPreview.slice(0, 200)}` : '';
118
+ const note = `Tool ${toolName} failed: ${errorType} (exitCode: ${exitCode})${previewSuffix}`;
119
+ evidence.push({
120
+ sourceRef: `tool_call_failure:${String(tc.created_at ?? 'unknown')}`,
121
+ note: sanitizeString(note.slice(0, MAX_EVIDENCE_NOTE_CHARS), workspaceDir),
122
+ });
153
123
  }
154
- // If no evidence at all from trajectory, provide a meaningful placeholder
124
+ }
125
+ catch {
126
+ readFailed = true;
127
+ // tool_calls table may not exist — degrade gracefully (only when no other evidence)
155
128
  if (evidence.length === 0) {
156
129
  evidence.push({
157
- sourceRef: 'trajectory:empty',
158
- note: 'trajectory_available_but_empty: no user correction or assistant turns found',
130
+ sourceRef: 'tool_call_failure:unavailable',
131
+ note: 'trajectory_tool_calls_unavailable',
159
132
  });
160
133
  }
161
- return evidence.slice(0, MAX_EVIDENCE_ENTRIES);
134
+ }
135
+ // If no evidence at all from trajectory, provide a meaningful placeholder
136
+ if (evidence.length === 0) {
137
+ evidence.push({
138
+ sourceRef: 'trajectory:empty',
139
+ note: 'trajectory_available_but_empty: no user correction or assistant turns found',
140
+ });
141
+ }
142
+ const bounded = evidence.slice(0, MAX_EVIDENCE_ENTRIES);
143
+ const realEntryCount = bounded.reduce((count, entry) => count + (PLACEHOLDER_SOURCE_REFS.has(entry.sourceRef) ? 0 : 1), 0);
144
+ return { entries: bounded, realEntryCount, readFailed };
145
+ }
146
+ /**
147
+ * PRI-642 Scope A typed acquisition from trajectory.db (SPEC §7.3).
148
+ *
149
+ * Validates that the requested session exists in the trajectory `sessions`
150
+ * table (every recorded turn/tool call upserts its session row, so an absent
151
+ * row means the session was never seen) and classifies the outcome:
152
+ * - `available` — session bound, ≥1 real behavior-trace entry;
153
+ * - `session_not_found` — session absent from the sessions table (or a
154
+ * `cli`/`unknown` sentinel — never a real session);
155
+ * - `trajectory_unavailable` — no trajectory.db in this workspace;
156
+ * - `evidence_read_failed` — the DB exists but cannot be opened/read;
157
+ * - `empty_trajectory` — real session, no usable evidence rows.
158
+ */
159
+ export function acquireTrajectoryEvidenceFromDb(stateDir, sessionId, workspaceDir) {
160
+ if (!sessionId || sessionId === 'cli' || sessionId === 'unknown') {
161
+ return {
162
+ status: 'unavailable',
163
+ reasonCode: 'session_not_found',
164
+ detail: sessionId ? `sentinel_session_id:${sessionId}` : 'missing_session_id',
165
+ };
166
+ }
167
+ const dbPath = path.join(stateDir, 'trajectory.db');
168
+ if (!fs.existsSync(dbPath)) {
169
+ return {
170
+ status: 'unavailable',
171
+ reasonCode: 'trajectory_unavailable',
172
+ detail: 'trajectory_db_missing',
173
+ };
174
+ }
175
+ let db;
176
+ try {
177
+ db = new Database(dbPath, { readonly: true });
178
+ }
179
+ catch (err) {
180
+ return {
181
+ status: 'unavailable',
182
+ reasonCode: 'evidence_read_failed',
183
+ detail: `trajectory_db_unreadable: ${err instanceof Error ? err.message : String(err)}`,
184
+ };
185
+ }
186
+ try {
187
+ // Session existence: rows are upserted by every turn/tool-call write, so
188
+ // an absent row means the trajectory never saw this session.
189
+ let sessionExists = false;
190
+ try {
191
+ const row = db.prepare('SELECT 1 FROM sessions WHERE session_id = ?').get(sessionId);
192
+ sessionExists = row !== undefined;
193
+ }
194
+ catch {
195
+ // sessions table missing → cannot validate existence; fall through and
196
+ // let the evidence rows decide (legacy DBs may lack the table).
197
+ sessionExists = true;
198
+ }
199
+ if (!sessionExists) {
200
+ return {
201
+ status: 'unavailable',
202
+ reasonCode: 'session_not_found',
203
+ detail: 'session_not_present_in_trajectory',
204
+ };
205
+ }
206
+ const collection = collectEvidenceFromDb(db, sessionId, workspaceDir);
207
+ if (collection.realEntryCount > 0) {
208
+ return { status: 'available', entries: collection.entries };
209
+ }
210
+ if (collection.readFailed) {
211
+ return {
212
+ status: 'unavailable',
213
+ reasonCode: 'evidence_read_failed',
214
+ detail: 'trajectory_tables_unreadable',
215
+ };
216
+ }
217
+ return {
218
+ status: 'unavailable',
219
+ reasonCode: 'empty_trajectory',
220
+ detail: 'session_present_but_no_usable_evidence',
221
+ };
162
222
  }
163
223
  finally {
164
224
  db.close();
@@ -1 +1 @@
1
- {"version":3,"file":"build-trajectory-evidence.js","sourceRoot":"","sources":["../../src/commands/build-trajectory-evidence.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"build-trajectory-evidence.js","sourceRoot":"","sources":["../../src/commands/build-trajectory-evidence.ts"],"names":[],"mappings":"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"}
@@ -15,6 +15,19 @@ interface ConsoleOptions {
15
15
  noAuth?: boolean;
16
16
  json?: boolean;
17
17
  }
18
+ /**
19
+ * Verify the console server's runtime dependency slots are resolvable.
20
+ *
21
+ * The console's dist statically imports `@principles/core/runtime-v2` and
22
+ * `@principles/host-runtime`, and reads plugin governance exports from
23
+ * `principles-disciple`. Each slot must be a real package (package.json present
24
+ * AND dist/index.js present) — a dangling junction or an empty shell (package.json
25
+ * without dist) makes the server crash with ERR_MODULE_NOT_FOUND at startup.
26
+ *
27
+ * Returns a human-readable description of the first broken slot, or undefined
28
+ * when everything is resolvable.
29
+ */
30
+ export declare function checkConsoleRuntimeDependencies(consoleDir: string): string | undefined;
18
31
  export declare function handleConsole(opts?: ConsoleOptions): Promise<void>;
19
32
  /**
20
33
  * Launch (or reuse) the PD Console with seed-friendly defaults:
@@ -1 +1 @@
1
- {"version":3,"file":"console.d.ts","sourceRoot":"","sources":["../../src/commands/console.ts"],"names":[],"mappings":"AAwBA,UAAU,kBAAkB;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,kCAAkC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kDAAkD;IAClD,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAID,UAAU,cAAc;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAuBD,wBAAsB,aAAa,CAAC,IAAI,GAAE,cAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAoH5E;AAID;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,GAAE,kBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CAydpF"}
1
+ {"version":3,"file":"console.d.ts","sourceRoot":"","sources":["../../src/commands/console.ts"],"names":[],"mappings":"AAwBA,UAAU,kBAAkB;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,kCAAkC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kDAAkD;IAClD,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAID,UAAU,cAAc;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAuBD;;;;;;;;;;;GAWG;AACH,wBAAgB,+BAA+B,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAqCtF;AAED,wBAAsB,aAAa,CAAC,IAAI,GAAE,cAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAyI5E;AAID;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,GAAE,kBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CA0fpF"}
@@ -30,6 +30,56 @@ function getConsoleDir() {
30
30
  const dir = resolved.mode === 'canonical' ? paths.consoleDir : path.join(paths.openClawExtensionDir, 'console');
31
31
  return { dir, mode: resolved.mode };
32
32
  }
33
+ /**
34
+ * Verify the console server's runtime dependency slots are resolvable.
35
+ *
36
+ * The console's dist statically imports `@principles/core/runtime-v2` and
37
+ * `@principles/host-runtime`, and reads plugin governance exports from
38
+ * `principles-disciple`. Each slot must be a real package (package.json present
39
+ * AND dist/index.js present) — a dangling junction or an empty shell (package.json
40
+ * without dist) makes the server crash with ERR_MODULE_NOT_FOUND at startup.
41
+ *
42
+ * Returns a human-readable description of the first broken slot, or undefined
43
+ * when everything is resolvable.
44
+ */
45
+ export function checkConsoleRuntimeDependencies(consoleDir) {
46
+ // These are the exact entry files the console server resolves at startup,
47
+ // derived from each package's real `exports` map (not assumed dist/index.js):
48
+ // @principles/core/principle-tree-ledger → dist/principle-tree-ledger.js
49
+ // @principles/core/runtime-v2 → dist/runtime-v2/index.js
50
+ // @principles/host-runtime → dist/index.js
51
+ // @principles/install-layout → dist/index.js
52
+ // principles-disciple/governance-audit → dist/governance-audit.js
53
+ // Checking the real resolved entries (not just dist/index.js) catches broken
54
+ // shells where package.json exists but the actual import target is missing.
55
+ // One package can have multiple required entries (@principles/core).
56
+ const slots = [
57
+ {
58
+ pkg: '@principles/core',
59
+ entries: [
60
+ path.join('dist', 'principle-tree-ledger.js'),
61
+ path.join('dist', 'runtime-v2', 'index.js'),
62
+ ],
63
+ },
64
+ { pkg: '@principles/host-runtime', entries: [path.join('dist', 'index.js')] },
65
+ { pkg: '@principles/install-layout', entries: [path.join('dist', 'index.js')] },
66
+ { pkg: 'principles-disciple', entries: [path.join('dist', 'governance-audit.js')] },
67
+ ];
68
+ for (const slot of slots) {
69
+ const base = path.join(consoleDir, 'node_modules', slot.pkg);
70
+ const pkgJson = path.join(base, 'package.json');
71
+ if (!fs.existsSync(pkgJson)) {
72
+ return `console/node_modules/${slot.pkg}/package.json is missing`;
73
+ }
74
+ for (const entry of slot.entries) {
75
+ const entryFile = path.join(base, entry);
76
+ if (!fs.existsSync(entryFile)) {
77
+ return `console/node_modules/${slot.pkg}/${entry.replaceAll('\\', '/')} is missing (incomplete package)`;
78
+ }
79
+ }
80
+ }
81
+ return undefined;
82
+ }
33
83
  export async function handleConsole(opts = {}) {
34
84
  const workspaceDir = opts.workspace
35
85
  ? path.resolve(opts.workspace)
@@ -73,6 +123,27 @@ export async function handleConsole(opts = {}) {
73
123
  process.exit(1);
74
124
  return;
75
125
  }
126
+ // Runtime dependency integrity check: the console server statically imports
127
+ // @principles/core/runtime-v2 and @principles/host-runtime, and the console
128
+ // reads plugin governance exports from principles-disciple. When the OpenClaw
129
+ // upgrade path refreshes the plugin bundle without re-running the PD installer
130
+ // (2026-09: console_cli_exited_before_result), these node_modules slots can be
131
+ // left as an empty shell (package.json without dist) or a dangling junction.
132
+ // The server then crashes with ERR_MODULE_NOT_FOUND at startup, which the
133
+ // Companion reports as the opaque console_cli_exited_before_result. Fail loud
134
+ // here with the actionable repair command instead.
135
+ const integrityError = checkConsoleRuntimeDependencies(consoleLocation.dir);
136
+ if (integrityError) {
137
+ const msg = `Console runtime dependency broken: ${integrityError}. Re-run installer to repair.`;
138
+ if (opts.json) {
139
+ console.log(JSON.stringify({ success: false, reason: msg, nextAction: 'npx create-principles-disciple' }));
140
+ }
141
+ else {
142
+ console.error(msg);
143
+ }
144
+ process.exit(1);
145
+ return;
146
+ }
76
147
  const port = opts.port || '3100';
77
148
  const host = '127.0.0.1';
78
149
  const args = [serverEntry, '--workspace', workspaceDir, '--port', port, '--host', host];
@@ -456,6 +527,39 @@ export async function handleConsoleOpen(opts = {}) {
456
527
  return;
457
528
  }
458
529
  // 5) Fresh spawn path
530
+ // Runtime dependency integrity check — only here, NOT before the reuse
531
+ // probe above. A healthy console already running (reused) has its modules
532
+ // loaded in memory; broken disk slots (dangling junction / empty shell left
533
+ // by an interrupted update) must not prevent reusing it. Only when we are
534
+ // about to execute the local console bytes do the local bytes need to be
535
+ // resolvable. The server statically imports @principles/core/runtime-v2 and
536
+ // @principles/host-runtime, and reads plugin governance exports from
537
+ // principles-disciple; without this check a broken install crashes with
538
+ // ERR_MODULE_NOT_FOUND which the Companion reports as the opaque
539
+ // console_cli_exited_before_result.
540
+ const integrityError = checkConsoleRuntimeDependencies(consoleLocation.dir);
541
+ if (integrityError) {
542
+ const result = {
543
+ status: 'failed',
544
+ url: '',
545
+ port: plan.port,
546
+ host: plan.host,
547
+ workspaceDir,
548
+ reused: false,
549
+ browserOpened: false,
550
+ reason: 'console_runtime_dependency_broken',
551
+ nextAction: `Re-run installer: npx create-principles-disciple (${integrityError})`,
552
+ };
553
+ if (opts.json) {
554
+ console.log(JSON.stringify(result, null, 2));
555
+ }
556
+ else {
557
+ console.error(`error: ${result.reason}`);
558
+ console.error(`next: ${result.nextAction}`);
559
+ }
560
+ process.exit(1);
561
+ return;
562
+ }
459
563
  const args = [serverEntry, '--workspace', workspaceDir, '--port', String(plan.port), '--host', plan.host];
460
564
  if (opts.noAuth)
461
565
  args.push('--no-auth');