log-llm-config 1.3.7 → 1.3.8

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.
@@ -2,9 +2,9 @@ import { appendFileSync, mkdirSync, existsSync } from 'node:fs';
2
2
  import { join } from 'node:path';
3
3
  import { homedir } from 'node:os';
4
4
  import { OPT_AI_SEC_MANAGEMENT_REL } from './bootstrap_constants.js';
5
- import { hookLogSessionBanner } from './log_config_files/runtime/hook_logger.js';
5
+ import { hookLogAppendSection } from './log_config_files/runtime/hook_logger.js';
6
6
  import { runComplianceCheck } from './log_config_files/runtime/compliance_check.js';
7
- /** Append-only log for compliance runner lifecycle; hook_log.txt is also append-only (session banners). */
7
+ /** Append-only log for compliance runner lifecycle; hook_log.txt uses a fresh session from the gate then this section. */
8
8
  function runnerFileLog(message) {
9
9
  try {
10
10
  const dir = join(homedir(), OPT_AI_SEC_MANAGEMENT_REL);
@@ -18,7 +18,7 @@ function runnerFileLog(message) {
18
18
  }
19
19
  }
20
20
  (async () => {
21
- hookLogSessionBanner('compliance_check_runner (background sync + check)');
21
+ hookLogAppendSection('compliance_check_runner (background sync + check)');
22
22
  runnerFileLog('compliance_check_runner: start');
23
23
  try {
24
24
  await runComplianceCheck();
@@ -6,14 +6,13 @@
6
6
  * and remediation_instructions.json via applyAutofixViolations / enforceRemediation.
7
7
  *
8
8
  * Prompt gate: compliance_prompt_gate runs runLocalRemediationComplianceCheck then applyAutofixViolations.
9
- * Background: compliance_check_runner runs syncRemediations (network), the same local check, then
10
- * applyAutofixViolations + executeTrustedRestartCommands so remediations apply even when only the
11
- * background path runs (sqlite/vscdb updates remain Cursor-specific; restarts use the shared allowlist).
9
+ * Background: compliance_check_runner runs syncRemediations (network) then the same local check.
10
+ * Apply (autofix) is intentionally left to the gate on the next prompt — the background pass only
11
+ * downloads the latest manifest so the gate has fresh data to act on.
12
12
  */
13
- import { existsSync, readFileSync, statSync } from 'node:fs';
13
+ import { existsSync, readFileSync } from 'node:fs';
14
14
  import { readVscdbItemTableJson } from '../readers/vscdb_reader.js';
15
- import { getRemediationInstructionsPath, readRemediationInstructionsFile, writeRemediationInstructionsFile, } from './management_storage.js';
16
- import { executeTrustedRestartCommands } from './trusted_restarts.js';
15
+ import { readRemediationInstructionsFile, writeRemediationInstructionsFile } from './management_storage.js';
17
16
  import { complianceRunnerDiag, hookRunLog } from './hook_logger.js';
18
17
  import { loadEndpointBase } from '../sender/endpoint_config.js';
19
18
  import { resolveHardwareUuid, tryResolveHardwareUuid } from './hardware_uuid.js';
@@ -434,22 +433,10 @@ export function pruneSatisfiedOneTimeRemediations() {
434
433
  }
435
434
  return { removed, reportPromises };
436
435
  }
437
- /** Same staleness window as compliance_prompt_gate: avoid applying very old local manifests. */
438
- const MANIFEST_STALE_MS = 7 * 24 * 60 * 60 * 1000;
439
- function getManifestStalenessMs() {
440
- try {
441
- const p = getRemediationInstructionsPath();
442
- if (!existsSync(p))
443
- return null;
444
- return Date.now() - statSync(p).mtimeMs;
445
- }
446
- catch {
447
- return null;
448
- }
449
- }
450
436
  /**
451
- * Background refresh: server sync, local evaluation, then autofix + trusted restarts (same enforcement
452
- * as the prompt gate, without blocking stdin/stdout for the IDE).
437
+ * Background refresh: server sync for latest instructions, then the same local evaluation as the hook.
438
+ * Apply (autofix) is intentionally deferred to the gate on the next prompt — this pass only downloads
439
+ * a fresh manifest so the gate has up-to-date data when it runs.
453
440
  */
454
441
  export async function runComplianceCheck() {
455
442
  try {
@@ -464,31 +451,5 @@ export async function runComplianceCheck() {
464
451
  if (pruned.removed > 0) {
465
452
  await Promise.allSettled(pruned.reportPromises);
466
453
  }
467
- return;
468
- }
469
- const staleMs = getManifestStalenessMs();
470
- if (staleMs !== null && staleMs > MANIFEST_STALE_MS) {
471
- const staleDays = Math.floor(staleMs / (24 * 60 * 60 * 1000));
472
- hookRunLog(`compliance_check_runner: skip autofix — local remediation manifest is stale (${staleDays} days old)`);
473
- return;
474
- }
475
- const { fixed, restartCommands, failedViolations, reportPromises } = applyAutofixViolations(status.violations);
476
- if (fixed === 0) {
477
- if (failedViolations.length > 0) {
478
- hookRunLog(`compliance_check_runner: autofix failed for ${failedViolations.length} violation(s) (see autofix logs above)`);
479
- }
480
- return;
481
- }
482
- await Promise.allSettled(reportPromises);
483
- if (failedViolations.length > 0) {
484
- hookRunLog(`compliance_check_runner: autofix partial failure — ${failedViolations.length} violation(s) still unresolved`);
485
- }
486
- if (restartCommands.length > 0) {
487
- hookRunLog(`compliance_check_runner: executing ${restartCommands.length} trusted restart command(s)`);
488
- executeTrustedRestartCommands(restartCommands);
489
- }
490
- const pruned = pruneSatisfiedOneTimeRemediations();
491
- if (pruned.removed > 0) {
492
- await Promise.allSettled(pruned.reportPromises);
493
454
  }
494
455
  }
@@ -1,8 +1,10 @@
1
- import { existsSync, mkdirSync, appendFileSync } from 'node:fs';
1
+ import { existsSync, mkdirSync, appendFileSync, writeFileSync, statSync } from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { OPT_AI_SEC_MANAGEMENT_REL } from '../../bootstrap_constants.js';
4
4
  const HOOK_LOG_FILENAME = 'hook_log.txt';
5
5
  const COMPLIANCE_RUNNER_LOG_FILENAME = 'compliance_runner.log';
6
+ /** Hard cap so a single upload/sync session cannot grow hook_log.txt without bound. */
7
+ const MAX_HOOK_LOG_BYTES = 2 * 1024 * 1024;
6
8
  function getHookLogPath() {
7
9
  const homeDir = process.env.HOME || process.env.USERPROFILE;
8
10
  if (!homeDir)
@@ -33,7 +35,24 @@ function complianceRunnerDiag(message) {
33
35
  // best-effort
34
36
  }
35
37
  }
36
- /** Visible delimiter between hook_log.txt sessions (compliance gate, upload, etc.). */
38
+ function ensureHookLogUnderCap() {
39
+ const logPath = getHookLogPath();
40
+ if (!logPath || !existsSync(logPath))
41
+ return;
42
+ try {
43
+ if (statSync(logPath).size <= MAX_HOOK_LOG_BYTES)
44
+ return;
45
+ const ts = new Date().toISOString();
46
+ writeFileSync(logPath, `${'='.repeat(72)}\n${ts} hook_log.txt truncated (exceeded ${MAX_HOOK_LOG_BYTES} bytes)\n${'='.repeat(72)}\n`, 'utf8');
47
+ }
48
+ catch {
49
+ // best-effort
50
+ }
51
+ }
52
+ /**
53
+ * Start a new hook_log.txt session (replaces the file). Use once per logical run
54
+ * (e.g. compliance_prompt_gate, log_config_files upload via hookLogReplace).
55
+ */
37
56
  function hookLogSessionBanner(label) {
38
57
  const logPath = getHookLogPath();
39
58
  if (!logPath)
@@ -44,15 +63,34 @@ function hookLogSessionBanner(label) {
44
63
  mkdirSync(dir, { recursive: true, mode: 0o700 });
45
64
  const ts = new Date().toISOString();
46
65
  const banner = `\n${'='.repeat(72)}\n${ts} session: ${label}\n${'='.repeat(72)}\n`;
47
- appendFileSync(logPath, banner, 'utf8');
66
+ writeFileSync(logPath, banner, 'utf8');
48
67
  }
49
68
  catch {
50
69
  // best-effort
51
70
  }
52
71
  }
53
72
  /**
54
- * @deprecated Name kept for callers: begins a log_config_files upload section (append-only, does not truncate).
73
+ * Append a subsection after an existing session (e.g. compliance_check_runner after the gate)
74
+ * without replacing hook_log.txt.
55
75
  */
76
+ function hookLogAppendSection(label) {
77
+ const logPath = getHookLogPath();
78
+ if (!logPath)
79
+ return;
80
+ try {
81
+ ensureHookLogUnderCap();
82
+ const dir = path.dirname(logPath);
83
+ if (!existsSync(dir))
84
+ mkdirSync(dir, { recursive: true, mode: 0o700 });
85
+ const ts = new Date().toISOString();
86
+ const banner = `\n${'-'.repeat(72)}\n${ts} section: ${label}\n${'-'.repeat(72)}\n`;
87
+ appendFileSync(logPath, banner, 'utf8');
88
+ }
89
+ catch {
90
+ // best-effort
91
+ }
92
+ }
93
+ /** Begins a log_config_files upload session (replaces hook_log.txt, same as hookLogSessionBanner). */
56
94
  function hookLogReplace() {
57
95
  hookLogSessionBanner('log_config_files (config upload)');
58
96
  }
@@ -62,6 +100,7 @@ function hookRunLog(message) {
62
100
  if (!logPath)
63
101
  return;
64
102
  try {
103
+ ensureHookLogUnderCap();
65
104
  const ts = new Date().toISOString();
66
105
  appendFileSync(logPath, `${ts} ${message}\n`, 'utf8');
67
106
  }
@@ -75,10 +114,11 @@ function hookLogLine(message) {
75
114
  if (!logPath)
76
115
  return;
77
116
  try {
117
+ ensureHookLogUnderCap();
78
118
  appendFileSync(logPath, `${message}\n`, 'utf8');
79
119
  }
80
120
  catch {
81
121
  // best-effort
82
122
  }
83
123
  }
84
- export { getHookLogPath, getComplianceRunnerLogPath, hookLogReplace, hookLogSessionBanner, hookRunLog, hookLogLine, complianceRunnerDiag, };
124
+ export { getHookLogPath, getComplianceRunnerLogPath, hookLogReplace, hookLogSessionBanner, hookLogAppendSection, hookRunLog, hookLogLine, complianceRunnerDiag, };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "log-llm-config",
3
- "version": "1.3.7",
3
+ "version": "1.3.8",
4
4
  "description": "CLI helpers for logging hardware UUIDs and posting startup payloads to Optimus Security.",
5
5
  "type": "module",
6
6
  "bin": {