log-llm-config 1.3.24 → 1.3.26
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 +2 -2
- package/dist/compliance_check_runner.js +5 -29
- package/dist/execute_trusted_restarts.js +14 -5
- package/dist/log_config_files/runtime/compliance_check.js +26 -3
- package/dist/log_config_files/runtime/hook_logger.js +26 -8
- package/dist/log_config_files/runtime/management_storage.js +5 -0
- package/dist/log_config_files/runtime/remediation_sync.js +7 -3
- package/dist/log_config_files/runtime/trusted_restarts.js +34 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ Collects the machine hardware UUID (or uses the `OPTIMUS_HARDWARE_UUID` env vari
|
|
|
15
15
|
|
|
16
16
|
```bash
|
|
17
17
|
OPTIMUS_ENDPOINT=http://localhost:8080/endpoint_security/ \
|
|
18
|
-
npx log-llm-config log_uuid
|
|
18
|
+
npx --yes log-llm-config@latest log_uuid
|
|
19
19
|
```
|
|
20
20
|
|
|
21
21
|
- **Optional flags** (for git context, similar to `optimus-init`):
|
|
@@ -32,7 +32,7 @@ Legacy helper that logs local Optimus/Cursor configuration files to `configs.txt
|
|
|
32
32
|
You can also pass the UUID explicitly:
|
|
33
33
|
|
|
34
34
|
```bash
|
|
35
|
-
npx log-llm-config log_uuid --uuid "DUMMY-LOCAL-UUID"
|
|
35
|
+
npx --yes log-llm-config@latest log_uuid --uuid "DUMMY-LOCAL-UUID"
|
|
36
36
|
```
|
|
37
37
|
|
|
38
38
|
### Development
|
|
@@ -1,40 +1,16 @@
|
|
|
1
|
-
import {
|
|
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
|
-
|
|
5
|
+
complianceRunnerRunnerLine('compliance_check_runner: start');
|
|
23
6
|
try {
|
|
24
7
|
await runComplianceCheck();
|
|
25
|
-
|
|
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
|
-
|
|
30
|
-
|
|
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
|
}
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
29
|
+
* Append one ISO-timestamped line to compliance_runner.log.
|
|
30
|
+
* `level` examples: INFO, RUNNER, RESTART, FAIL
|
|
30
31
|
*/
|
|
31
|
-
function
|
|
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
|
|
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
|
-
|
|
91
|
+
writeFailAppend(failPath);
|
|
79
92
|
const crPath = getComplianceRunnerLogPath();
|
|
80
|
-
if (crPath)
|
|
81
|
-
|
|
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
|
}
|
|
@@ -362,8 +362,10 @@ function assertSafeSqliteIdentifiersForItemTable(table, keyColumn, valueColumn)
|
|
|
362
362
|
* Exact-match only: `spawn('sh', ['-c', cmd])` runs the whole string; substring checks would allow
|
|
363
363
|
* appending `; arbitrary shell` after a trusted prefix.
|
|
364
364
|
*/
|
|
365
|
-
const TRUSTED_CURSOR_SQLITE_DEFERRED_RESTART_COMMAND = 'REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd) && export REPO_ROOT
|
|
366
|
-
|
|
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 log-llm-config@latest 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";
|
|
367
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';
|
|
368
370
|
const TRUSTED_CLAUDE_RESTART_COMMAND = "nohup bash -c 'sleep 2 && open -a Claude' >/dev/null 2>&1 & pkill -x 'Claude'";
|
|
369
371
|
/**
|
|
@@ -721,6 +723,8 @@ function queueDeferredVscdbItem(item, postApplyUpload) {
|
|
|
721
723
|
*/
|
|
722
724
|
export async function applyDeferredVscdbFromDisk() {
|
|
723
725
|
const path = getDeferredVscdbApplyPath();
|
|
726
|
+
hookRunLog(`deferred_vscdb: applyDeferredVscdbFromDisk queue_path=${path} exists=${existsSync(path)}`);
|
|
727
|
+
complianceRunnerDiag(`deferred_vscdb: applyDeferredVscdbFromDisk start exists=${existsSync(path)}`);
|
|
724
728
|
if (!existsSync(path))
|
|
725
729
|
return true;
|
|
726
730
|
if (!assertSqlite3Available())
|
|
@@ -804,7 +808,7 @@ export async function applyDeferredVscdbFromDisk() {
|
|
|
804
808
|
* is the JSON-settings-only Cursor template (kill + reopen, no `apply_deferred_vscdb`).
|
|
805
809
|
*/
|
|
806
810
|
export function buildDeferredCursorRestartCommand() {
|
|
807
|
-
// Prefer monorepo path when hooks run from optimus-secure-fdn; otherwise `npx
|
|
811
|
+
// Prefer monorepo path when hooks run from optimus-secure-fdn; otherwise `npx --yes log-llm-config@latest apply-deferred-vscdb`
|
|
808
812
|
// (package bin) so published installs work without a local npx_packages copy.
|
|
809
813
|
return TRUSTED_CURSOR_SQLITE_DEFERRED_RESTART_COMMAND;
|
|
810
814
|
}
|
|
@@ -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
|
-
|
|
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
|
-
|
|
19
|
-
const
|
|
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
|
}
|