log-llm-config 1.3.23 → 1.3.25

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.
@@ -1,40 +1,16 @@
1
- import { appendFileSync, mkdirSync, existsSync } from 'node:fs';
2
- import { join } from 'node:path';
3
- import { homedir } from 'node:os';
4
- import { OPT_AI_SEC_MANAGEMENT_REL } from './bootstrap_constants.js';
5
- import { hookLogAppendSection } from './log_config_files/runtime/hook_logger.js';
1
+ import { complianceRunnerRunnerLine, hookLogAppendSection } from './log_config_files/runtime/hook_logger.js';
6
2
  import { runComplianceCheck } from './log_config_files/runtime/compliance_check.js';
7
- /** Append-only log for compliance runner lifecycle; hook_log.txt uses a fresh session from the gate then this section. */
8
- function runnerFileLog(message) {
9
- try {
10
- const dir = join(homedir(), OPT_AI_SEC_MANAGEMENT_REL);
11
- if (!existsSync(dir))
12
- mkdirSync(dir, { recursive: true, mode: 0o700 });
13
- const path = join(dir, 'compliance_runner.log');
14
- appendFileSync(path, `${new Date().toISOString()} ${message}\n`, 'utf8');
15
- }
16
- catch {
17
- /* ignore */
18
- }
19
- }
20
3
  (async () => {
21
4
  hookLogAppendSection('compliance_check_runner (background sync + check)');
22
- runnerFileLog('compliance_check_runner: start');
5
+ complianceRunnerRunnerLine('compliance_check_runner: start');
23
6
  try {
24
7
  await runComplianceCheck();
25
- runnerFileLog('compliance_check_runner: finished ok');
8
+ complianceRunnerRunnerLine('compliance_check_runner: finished ok');
26
9
  }
27
10
  catch (err) {
28
11
  const detail = err instanceof Error ? err.stack ?? err.message : String(err);
29
- runnerFileLog('compliance_check_runner: uncaught error');
30
- try {
31
- const dir = join(homedir(), OPT_AI_SEC_MANAGEMENT_REL);
32
- const path = join(dir, 'compliance_runner.log');
33
- appendFileSync(path, `${detail}\n\n`, 'utf8');
34
- }
35
- catch {
36
- /* ignore */
37
- }
12
+ complianceRunnerRunnerLine(`compliance_check_runner: uncaught error — ${err instanceof Error ? err.message : String(err)}`);
13
+ complianceRunnerRunnerLine(`compliance_check_runner: stack_or_detail ${detail.slice(0, 4000)}`);
38
14
  process.stderr.write(`compliance_check_runner error: ${err instanceof Error ? err.message : String(err)}\n`);
39
15
  process.exit(1);
40
16
  }
@@ -1,3 +1,3 @@
1
1
  export { FILE_PATH_REGISTRY_FILE_PATTERNS_PATH, FILE_PATH_REGISTRY_SENSITIVE_PATHS_PATH, } from './types.js';
2
- export { getFileCollectionPatterns, getSensitivePathsAuditCandidates } from './registry_api.js';
2
+ export { buildApiUrl, getFileCollectionPatterns, getSensitivePathsAuditCandidates, } from './registry_api.js';
3
3
  export { postStartupPayload, patchPayload, classifyEndpointResponse } from './startup_api.js';
@@ -1,7 +1,11 @@
1
+ import { URL } from 'node:url';
1
2
  import { executeGet } from './http_transport.js';
2
3
  import { FILE_PATH_REGISTRY_FILE_PATTERNS_PATH, FILE_PATH_REGISTRY_SENSITIVE_PATHS_PATH, } from './types.js';
3
- function buildApiUrl(base, path) {
4
- return `${base.replace(/\/+$/, '')}${path}`.replace(/([^/])\/+/g, '$1/');
4
+ /** Join API base (may include a path prefix, e.g. https://host/optimus/) with an absolute API path. */
5
+ export function buildApiUrl(base, path) {
6
+ const normalizedBase = `${base.replace(/\/+$/, '')}/`;
7
+ const relativePath = path.replace(/^\/+/, '');
8
+ return new URL(relativePath, normalizedBase).href;
5
9
  }
6
10
  /**
7
11
  * GET file collection patterns from the backend (what to look for).
@@ -5,7 +5,7 @@
5
5
  */
6
6
  import { readFileSync } from 'node:fs';
7
7
  import { isThisCliModule } from './cli_invocation_match.js';
8
- import { hookRunLog } from './log_config_files/runtime/hook_logger.js';
8
+ import { appendComplianceRunnerLine, hookRunLog } from './log_config_files/runtime/hook_logger.js';
9
9
  import { executeTrustedRestartCommands } from './log_config_files/runtime/trusted_restarts.js';
10
10
  function main() {
11
11
  let raw;
@@ -13,24 +13,33 @@ function main() {
13
13
  raw = readFileSync(0, 'utf8');
14
14
  }
15
15
  catch {
16
- hookRunLog('execute_trusted_restarts: could not read stdin');
16
+ const msg = 'execute_trusted_restarts: could not read stdin';
17
+ hookRunLog(msg);
18
+ appendComplianceRunnerLine('RESTART', msg);
17
19
  return;
18
20
  }
19
21
  const first = raw.trim().split(/\r?\n/)[0]?.trim() ?? '';
20
- if (!first)
22
+ if (!first) {
23
+ appendComplianceRunnerLine('RESTART', 'empty stdin — no restart_commands');
21
24
  return;
25
+ }
22
26
  let j;
23
27
  try {
24
28
  j = JSON.parse(first);
25
29
  }
26
30
  catch {
27
- hookRunLog('execute_trusted_restarts: stdin is not valid JSON');
31
+ const msg = 'execute_trusted_restarts: stdin is not valid JSON';
32
+ hookRunLog(msg);
33
+ appendComplianceRunnerLine('RESTART', msg);
28
34
  return;
29
35
  }
30
36
  const cmds = j.restart_commands;
31
- if (!Array.isArray(cmds))
37
+ if (!Array.isArray(cmds)) {
38
+ appendComplianceRunnerLine('RESTART', 'JSON missing restart_commands array — nothing to run');
32
39
  return;
40
+ }
33
41
  const strings = cmds.filter((c) => typeof c === 'string');
42
+ appendComplianceRunnerLine('RESTART', `stdin ok restart_commands=${strings.length}`);
34
43
  executeTrustedRestartCommands(strings);
35
44
  }
36
45
  if (isThisCliModule(process.argv[1], import.meta.url)) {
@@ -143,19 +143,29 @@ export function runLocalRemediationComplianceCheck() {
143
143
  }
144
144
  const uuids = entries.map((e) => e.uuid);
145
145
  const violations = [];
146
+ let skippedNoCompliance = 0;
147
+ let skippedNonJson = 0;
148
+ let skippedNoChecks = 0;
149
+ let skippedUnreadable = 0;
146
150
  for (const entry of entries) {
147
151
  const compliance = entry.fix ?? entry.compliance;
148
- if (!compliance)
152
+ if (!compliance) {
153
+ skippedNoCompliance++;
149
154
  continue;
155
+ }
150
156
  if (compliance.file_format !== 'json') {
157
+ skippedNonJson++;
151
158
  hookRunLog(`compliance_check: skipping non-json entry uuid=${entry.uuid}`);
152
159
  continue;
153
160
  }
154
161
  const checks = compliance.checks ?? [];
155
- if (checks.length === 0)
162
+ if (checks.length === 0) {
163
+ skippedNoChecks++;
156
164
  continue;
165
+ }
157
166
  const loaded = loadRemediationConfigJson(entry.config_file_path, checks.map((c) => c.setting_path));
158
167
  if (!loaded.ok) {
168
+ skippedUnreadable++;
159
169
  const msg = loaded.reason === 'file_not_found'
160
170
  ? `compliance_check: config file not found, skipping uuid=${entry.uuid}`
161
171
  : loaded.reason === 'db_not_found'
@@ -228,7 +238,20 @@ export function runLocalRemediationComplianceCheck() {
228
238
  manifest_uuids: uuids,
229
239
  violations,
230
240
  };
231
- hookRunLog(`compliance_check: done status=${status.status} violations=${violations.length} uuids=${uuids.length}`);
241
+ const skipParts = [];
242
+ if (skippedNoCompliance)
243
+ skipParts.push(`no_fix=${skippedNoCompliance}`);
244
+ if (skippedNonJson)
245
+ skipParts.push(`non_json=${skippedNonJson}`);
246
+ if (skippedNoChecks)
247
+ skipParts.push(`no_checks=${skippedNoChecks}`);
248
+ if (skippedUnreadable)
249
+ skipParts.push(`unreadable_config=${skippedUnreadable}`);
250
+ const skipSummary = skipParts.length > 0 ? ` skipped{${skipParts.join(' ')}}` : '';
251
+ hookRunLog(`compliance_check: done — status=${status.status} violations=${violations.length} manifest_entries=${uuids.length}${skipSummary}`);
252
+ if (skippedUnreadable > 0) {
253
+ complianceRunnerDiag(`compliance_check: ${skippedUnreadable} manifest row(s) skipped — vscdb/config unreadable (often DB locked while Cursor runs, or sqlite3/PATH). Autofix cannot evaluate until read succeeds.`);
254
+ }
232
255
  return status;
233
256
  }
234
257
  catch (err) {
@@ -26,9 +26,10 @@ function getRemediationApplyFailuresLogPath() {
26
26
  return path.join(homeDir, OPT_AI_SEC_MANAGEMENT_REL, REMEDIATION_APPLY_FAILURES_FILENAME);
27
27
  }
28
28
  /**
29
- * Append-only diagnostics (not truncated by main_runner). Use for remediation sync / compliance.
29
+ * Append one ISO-timestamped line to compliance_runner.log.
30
+ * `level` examples: INFO, RUNNER, RESTART, FAIL
30
31
  */
31
- function complianceRunnerDiag(message) {
32
+ function appendComplianceRunnerLine(level, message) {
32
33
  const logPath = getComplianceRunnerLogPath();
33
34
  if (!logPath)
34
35
  return;
@@ -37,12 +38,24 @@ function complianceRunnerDiag(message) {
37
38
  if (!existsSync(dir))
38
39
  mkdirSync(dir, { recursive: true, mode: 0o700 });
39
40
  const ts = new Date().toISOString();
40
- appendFileSync(logPath, `${ts} ${message}\n`, 'utf8');
41
+ appendFileSync(logPath, `${ts} [${level}] pid=${process.pid} ${message}\n`, 'utf8');
41
42
  }
42
43
  catch {
43
44
  // best-effort
44
45
  }
45
46
  }
47
+ /**
48
+ * Append-only diagnostics for remediation sync / compliance (structured).
49
+ */
50
+ function complianceRunnerDiag(message) {
51
+ appendComplianceRunnerLine('INFO', message);
52
+ }
53
+ /**
54
+ * Background compliance_check_runner should use this so entries match the same format.
55
+ */
56
+ function complianceRunnerRunnerLine(message) {
57
+ appendComplianceRunnerLine('RUNNER', message);
58
+ }
46
59
  /**
47
60
  * Loud, append-only record when a remediation cannot be verified or applied. Writes
48
61
  * {@link REMEDIATION_APPLY_FAILURES_FILENAME} and mirrors the same block to compliance_runner.log;
@@ -66,7 +79,7 @@ function logRemediationApplyFailure(context, fields) {
66
79
  : fields.message != null
67
80
  ? String(fields.message)
68
81
  : 'see fields above';
69
- const writeAppend = (filePath) => {
82
+ const writeFailAppend = (filePath) => {
70
83
  const dir = path.dirname(filePath);
71
84
  if (!existsSync(dir))
72
85
  mkdirSync(dir, { recursive: true, mode: 0o700 });
@@ -75,10 +88,14 @@ function logRemediationApplyFailure(context, fields) {
75
88
  try {
76
89
  const failPath = getRemediationApplyFailuresLogPath();
77
90
  if (failPath)
78
- writeAppend(failPath);
91
+ writeFailAppend(failPath);
79
92
  const crPath = getComplianceRunnerLogPath();
80
- if (crPath)
81
- writeAppend(crPath);
93
+ if (crPath) {
94
+ const dir = path.dirname(crPath);
95
+ if (!existsSync(dir))
96
+ mkdirSync(dir, { recursive: true, mode: 0o700 });
97
+ appendFileSync(crPath, block, 'utf8');
98
+ }
82
99
  }
83
100
  catch {
84
101
  /* best-effort */
@@ -89,6 +106,7 @@ function logRemediationApplyFailure(context, fields) {
89
106
  catch {
90
107
  /* best-effort */
91
108
  }
109
+ appendComplianceRunnerLine('FAIL', `${context} — ${summary}`);
92
110
  }
93
111
  function ensureHookLogUnderCap() {
94
112
  const logPath = getHookLogPath();
@@ -176,4 +194,4 @@ function hookLogLine(message) {
176
194
  // best-effort
177
195
  }
178
196
  }
179
- export { getHookLogPath, getComplianceRunnerLogPath, hookLogReplace, hookLogSessionBanner, hookLogAppendSection, hookRunLog, hookLogLine, complianceRunnerDiag, logRemediationApplyFailure, };
197
+ export { getHookLogPath, getComplianceRunnerLogPath, hookLogReplace, hookLogSessionBanner, hookLogAppendSection, hookRunLog, hookLogLine, complianceRunnerDiag, complianceRunnerRunnerLine, appendComplianceRunnerLine, logRemediationApplyFailure, };
@@ -9,6 +9,8 @@ import { OPT_AI_SEC_MANAGEMENT_REL } from '../../bootstrap_constants.js';
9
9
  export const REMEDIATION_INSTRUCTIONS_BASENAME = 'remediation_instructions.json';
10
10
  /** Pending state.vscdb writes applied after Cursor exits (IDE holds the DB locked). */
11
11
  export const DEFERRED_VSCDB_APPLY_BASENAME = 'optimus_deferred_vscdb_apply.json';
12
+ /** Shell stdout/stderr from the trusted deferred restart pipeline (apply_deferred_vscdb + open Cursor). */
13
+ export const DEFERRED_VSCDB_RESTART_LOG_BASENAME = 'deferred_vscdb_restart.log';
12
14
  /**
13
15
  * Cached subset of GET file-patterns: reactive ItemTable key + composer shadow keys from the backend.
14
16
  * Written when patterns are fetched; remediations and vscdb reads use this so the npm package stays free
@@ -24,6 +26,9 @@ export function getRemediationInstructionsPath() {
24
26
  export function getDeferredVscdbApplyPath() {
25
27
  return join(getManagementDir(), DEFERRED_VSCDB_APPLY_BASENAME);
26
28
  }
29
+ export function getDeferredVscdbRestartLogPath() {
30
+ return join(getManagementDir(), DEFERRED_VSCDB_RESTART_LOG_BASENAME);
31
+ }
27
32
  export function getFileCollectionVscdbContractPath() {
28
33
  return join(getManagementDir(), FILE_COLLECTION_VSCDB_CONTRACT_BASENAME);
29
34
  }
@@ -10,7 +10,7 @@ import { loadEndpointBase } from '../sender/endpoint_config.js';
10
10
  import { tryResolveHardwareUuid } from './hardware_uuid.js';
11
11
  import { CURSOR_SCALAR_ITEMTABLE_FIELDS, persistVscdbComposerContractFromPatternsResponse, readVscdbItemTableJson, } from '../readers/vscdb_reader.js';
12
12
  import { sendConfigFile } from '../sender/batch_sender.js';
13
- import { getFileCollectionPatterns } from '../../endpoint_client/registry_api.js';
13
+ import { buildApiUrl, getFileCollectionPatterns } from '../../endpoint_client/registry_api.js';
14
14
  import { resolveRemediationConfigPath } from './remediation_config_path.js';
15
15
  import { resolveSqlite3Binary } from './sqlite_binary.js';
16
16
  /** Best-effort detail from execFileSync failures (stderr, exit code, errno). */
@@ -119,17 +119,9 @@ async function ensureInstructionsForUuids(endpointBase, machineUuid, want, overl
119
119
  // ---------------------------------------------------------------------------
120
120
  // API helpers
121
121
  // ---------------------------------------------------------------------------
122
- function resolveOrigin(endpointBase) {
123
- try {
124
- return new URL(endpointBase).origin;
125
- }
126
- catch {
127
- return endpointBase.replace(/\/+$/, '');
128
- }
129
- }
130
122
  export async function fetchSync(endpointBase, machineUuid, activeUuids, timeoutMs = 8000) {
131
123
  const uuidsParam = activeUuids.join(',');
132
- const url = `${resolveOrigin(endpointBase)}/api/findings/remediations/sync/?machine_uuid=${encodeURIComponent(machineUuid)}&active_uuids=${encodeURIComponent(uuidsParam)}`;
124
+ const url = `${buildApiUrl(endpointBase, '/api/findings/remediations/sync/')}?machine_uuid=${encodeURIComponent(machineUuid)}&active_uuids=${encodeURIComponent(uuidsParam)}`;
133
125
  const { statusCode, body } = await executeGet(url, timeoutMs);
134
126
  if (statusCode !== 200 || !body) {
135
127
  const line = `remediation_sync_get: url=${url} status=${statusCode} bytes=${body?.length ?? 0}`;
@@ -147,7 +139,7 @@ export async function fetchSync(endpointBase, machineUuid, activeUuids, timeoutM
147
139
  }
148
140
  }
149
141
  async function fetchManifest(endpointBase, machineUuid, uuids, timeoutMs = 8000) {
150
- const url = `${resolveOrigin(endpointBase)}/api/findings/remediations/manifest/?machine_uuid=${encodeURIComponent(machineUuid)}&uuids=${encodeURIComponent(uuids.join(','))}`;
142
+ const url = `${buildApiUrl(endpointBase, '/api/findings/remediations/manifest/')}?machine_uuid=${encodeURIComponent(machineUuid)}&uuids=${encodeURIComponent(uuids.join(','))}`;
151
143
  const { statusCode, body } = await executeGet(url, timeoutMs);
152
144
  if (statusCode !== 200 || !body) {
153
145
  const line = `remediation_manifest_get: url=${url} status=${statusCode} bytes=${body?.length ?? 0}`;
@@ -370,8 +362,10 @@ function assertSafeSqliteIdentifiersForItemTable(table, keyColumn, valueColumn)
370
362
  * Exact-match only: `spawn('sh', ['-c', cmd])` runs the whole string; substring checks would allow
371
363
  * appending `; arbitrary shell` after a trusted prefix.
372
364
  */
373
- const TRUSTED_CURSOR_SQLITE_DEFERRED_RESTART_COMMAND = 'REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd) && export REPO_ROOT CURSOR_PROJECT="$REPO_ROOT" && ' +
374
- "nohup bash -c 'sleep 2; if [ -f \"$REPO_ROOT/npx_packages/log-llm-config/dist/apply_deferred_vscdb.js\" ]; then node \"$REPO_ROOT/npx_packages/log-llm-config/dist/apply_deferred_vscdb.js\"; else npx --yes -p log-llm-config apply-deferred-vscdb; fi || true; open -a Cursor \"$CURSOR_PROJECT\"' >/dev/null 2>&1 & killall -9 Cursor";
365
+ const TRUSTED_CURSOR_SQLITE_DEFERRED_RESTART_COMMAND = 'REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd) && export REPO_ROOT && ' +
366
+ 'CURSOR_PROJECT="${CURSOR_PROJECT_DIR:-$REPO_ROOT}" && export CURSOR_PROJECT && ' +
367
+ 'OPTIMUS_DEFERRED_LOG="${HOME}/opt-ai-sec/management/deferred_vscdb_restart.log" && mkdir -p "$(dirname "$OPTIMUS_DEFERRED_LOG")" && export OPTIMUS_DEFERRED_LOG && ' +
368
+ "nohup bash -c 'exec >>\"\$OPTIMUS_DEFERRED_LOG\" 2>&1; echo deferred_restart:begin ts=\$(date -u +%Y-%m-%dT%H:%M:%SZ) REPO_ROOT=\"\$REPO_ROOT\" CURSOR_PROJECT=\"\$CURSOR_PROJECT\"; sleep 2; if [ -f \"\$REPO_ROOT/npx_packages/log-llm-config/dist/apply_deferred_vscdb.js\" ]; then echo deferred_restart:apply_via_monorepo_node; node \"\$REPO_ROOT/npx_packages/log-llm-config/dist/apply_deferred_vscdb.js\"; APPLY_EC=\$?; else echo deferred_restart:apply_via_npx; cd \"\$REPO_ROOT\" && npx --yes -p log-llm-config apply-deferred-vscdb; APPLY_EC=\$?; fi; echo deferred_restart:apply_exit=\$APPLY_EC; if [ \$APPLY_EC -ne 0 ]; then echo deferred_restart:APPLY_FAILED_see_messages_above; fi; echo deferred_restart:open_cursor; open -a Cursor \"\$CURSOR_PROJECT\"; echo deferred_restart:open_exit=\$?; echo deferred_restart:end ts=\$(date -u +%Y-%m-%dT%H:%M:%SZ)' >/dev/null 2>&1 & killall -9 Cursor";
375
369
  const TRUSTED_CURSOR_JSON_SETTINGS_RESTART_COMMAND = 'CURSOR_PROJECT=$(git rev-parse --show-toplevel 2>/dev/null || pwd) && export CURSOR_PROJECT && nohup bash -c \'sleep 2 && open -a Cursor "$CURSOR_PROJECT"\' >/dev/null 2>&1 & killall -9 Cursor';
376
370
  const TRUSTED_CLAUDE_RESTART_COMMAND = "nohup bash -c 'sleep 2 && open -a Claude' >/dev/null 2>&1 & pkill -x 'Claude'";
377
371
  /**
@@ -729,6 +723,8 @@ function queueDeferredVscdbItem(item, postApplyUpload) {
729
723
  */
730
724
  export async function applyDeferredVscdbFromDisk() {
731
725
  const path = getDeferredVscdbApplyPath();
726
+ hookRunLog(`deferred_vscdb: applyDeferredVscdbFromDisk queue_path=${path} exists=${existsSync(path)}`);
727
+ complianceRunnerDiag(`deferred_vscdb: applyDeferredVscdbFromDisk start exists=${existsSync(path)}`);
732
728
  if (!existsSync(path))
733
729
  return true;
734
730
  if (!assertSqlite3Available())
@@ -1130,7 +1126,7 @@ export function reportAutofixApplied(remediationUuid, result) {
1130
1126
  return Promise.resolve();
1131
1127
  }
1132
1128
  const endpointBase = loadEndpointBase();
1133
- const url = `${resolveOrigin(endpointBase)}/endpoint_security/api/autofix-applied/`;
1129
+ const url = buildApiUrl(endpointBase, '/endpoint_security/api/autofix-applied/');
1134
1130
  const payload = { hardware_uuid: hardwareUuid, remediation_uuid: remediationUuid, result };
1135
1131
  const signature = createSignature(payload, authKey.key);
1136
1132
  const body = JSON.stringify({ ...payload, signature });
@@ -3,8 +3,13 @@
3
3
  * Used by the compliance shell hook via execute_trusted_restarts CLI — single place for allowlist + spawn.
4
4
  */
5
5
  import { spawn } from 'node:child_process';
6
- import { hookRunLog } from './hook_logger.js';
6
+ import { appendComplianceRunnerLine, hookRunLog } from './hook_logger.js';
7
+ import { getDeferredVscdbRestartLogPath } from './management_storage.js';
7
8
  import { isTrustedRestartCommandForAutofix } from './remediation_sync.js';
9
+ const FALLBACK_PATH = '/usr/bin:/bin:/usr/local/bin:/opt/homebrew/bin';
10
+ function isDeferredVscdbRestart(cmd) {
11
+ return cmd.includes('OPTIMUS_DEFERRED_LOG') || cmd.includes('apply_deferred_vscdb');
12
+ }
8
13
  /** Spawn each trusted command detached (same pattern as former compliance_prompt_gate fireRestartCommands). */
9
14
  export function executeTrustedRestartCommands(commands) {
10
15
  for (const cmd of commands) {
@@ -12,11 +17,36 @@ export function executeTrustedRestartCommands(commands) {
12
17
  if (!t)
13
18
  continue;
14
19
  if (!isTrustedRestartCommandForAutofix(cmd)) {
15
- hookRunLog(`execute_trusted_restarts: rejected (not allowlisted) prefix=${t.slice(0, 120)}`);
20
+ const msg = `rejected_not_allowlisted prefix=${t.slice(0, 200)}`;
21
+ hookRunLog(`execute_trusted_restarts: ${msg}`);
22
+ appendComplianceRunnerLine('RESTART', msg);
16
23
  continue;
17
24
  }
18
- hookRunLog(`execute_trusted_restarts: firing command="${t}"`);
19
- const child = spawn('sh', ['-c', t], { detached: true, stdio: 'ignore' });
25
+ const deferred = isDeferredVscdbRestart(t);
26
+ const detailPath = getDeferredVscdbRestartLogPath();
27
+ if (deferred) {
28
+ hookRunLog(`execute_trusted_restarts: spawning deferred state.vscdb restart (killall Cursor, then apply + reopen). Step-by-step log → ${detailPath}`);
29
+ appendComplianceRunnerLine('RESTART', `spawn deferred_vscdb_restart sh -c (detail_log=${detailPath}) cwd_inherited_from_node`);
30
+ }
31
+ else {
32
+ hookRunLog('execute_trusted_restarts: spawning trusted restart (see compliance_runner.log [RESTART])');
33
+ appendComplianceRunnerLine('RESTART', 'spawn trusted_restart sh -c (non-deferred)');
34
+ }
35
+ const child = spawn('sh', ['-c', t], {
36
+ detached: true,
37
+ stdio: 'ignore',
38
+ env: {
39
+ ...process.env,
40
+ PATH: process.env.PATH && String(process.env.PATH).trim().length > 0
41
+ ? process.env.PATH
42
+ : FALLBACK_PATH,
43
+ },
44
+ });
45
+ child.on('error', (err) => {
46
+ const emsg = err instanceof Error ? err.message : String(err);
47
+ hookRunLog(`execute_trusted_restarts: spawn failed ${emsg}`);
48
+ appendComplianceRunnerLine('RESTART', `spawn_error ${emsg}`);
49
+ });
20
50
  child.unref();
21
51
  }
22
52
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "log-llm-config",
3
- "version": "1.3.23",
3
+ "version": "1.3.25",
4
4
  "description": "CLI helpers for logging hardware UUIDs and posting startup payloads to Optimus Security.",
5
5
  "type": "module",
6
6
  "bin": {