@optimuslabs/harness-map-staging 1.5.39 → 1.5.40

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,7 +2,8 @@
2
2
  * Paths and JSON persistence for ~/.optimuslabs/management:
3
3
  * - remediation_instructions.json (remediations[])
4
4
  */
5
- import { existsSync, mkdirSync, readFileSync, renameSync, statSync, writeFileSync } from 'node:fs';
5
+ import { randomBytes } from 'node:crypto';
6
+ import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, statSync, writeFileSync } from 'node:fs';
6
7
  import { dirname, join } from 'node:path';
7
8
  import { homedir } from 'node:os';
8
9
  import { OPTIMUSLABS_MANAGEMENT_REL, OPTIMUSLABS_LOGS_REL } from '../../bootstrap_constants.js';
@@ -123,13 +124,23 @@ export function writeFileCollectionVscdbContract(contract) {
123
124
  return;
124
125
  atomicWriteJson(getFileCollectionVscdbContractPath(), sanitized);
125
126
  }
127
+ /**
128
+ * Write `data` as JSON to `filePath` in one step: to a temporary file of this write's own, then a
129
+ * rename. Two hooks writing at once (two Claude Code windows, the gate and the compliance runner)
130
+ * each use their own temporary file, so neither can rename the other's half-written one into place.
131
+ */
126
132
  export function atomicWriteJson(filePath, data) {
127
133
  const dir = dirname(filePath);
128
134
  if (!existsSync(dir))
129
135
  mkdirSync(dir, { recursive: true, mode: 0o700 });
130
- const tmp = `${filePath}.tmp`;
131
- writeFileSync(tmp, JSON.stringify(data, null, 2), 'utf8');
132
- renameSync(tmp, filePath);
136
+ const tmp = `${filePath}.${process.pid}.${randomBytes(4).toString('hex')}.tmp`;
137
+ try {
138
+ writeFileSync(tmp, JSON.stringify(data, null, 2), 'utf8');
139
+ renameSync(tmp, filePath);
140
+ }
141
+ finally {
142
+ rmSync(tmp, { force: true });
143
+ }
133
144
  }
134
145
  function parseInstructionsRaw(raw) {
135
146
  try {
@@ -16,11 +16,16 @@ import { basename } from 'node:path';
16
16
  import { atomicWriteJson, getSkillBlockProcessesPath, readRemediationInstructionsFile, } from './management_storage.js';
17
17
  import { launchAgentAccessWindow } from '../../agent_access/window_runner.js';
18
18
  import { quarantinedAt } from './skill_block.js';
19
- /** A process's parent, start time and command name, from `ps`; null when it cannot be read. */
20
- function processRow(pid) {
19
+ /**
20
+ * A process's parent, start time and command name, from `ps`; null when it cannot be read. `ps`
21
+ * writes the start time in the user's language ("Do. 5 Nov." in German), which the pattern below
22
+ * cannot read, so it runs in the C locale.
23
+ */
24
+ export function processRow(pid) {
21
25
  try {
26
+ const options = { encoding: 'utf8', env: { ...process.env, LC_ALL: 'C' } };
22
27
  // A fixed command, no shell, and a process id that is always a number.
23
- const out = execFileSync('ps', ['-o', 'ppid=,lstart=,comm=', '-p', String(pid)], { encoding: 'utf8' }).trim(); // nosafe: SAFE801
28
+ const out = execFileSync('ps', ['-o', 'ppid=,lstart=,comm=', '-p', String(pid)], options).trim(); // nosafe: SAFE801
24
29
  const row = out.match(/^(\d+)\s+(\S+\s+\S+\s+\d+\s+[\d:]+\s+\d+)\s+(.*)$/);
25
30
  return row ? { parent: Number(row[1]), startedAt: Date.parse(row[2]), name: basename(row[3]).toLowerCase() } : null;
26
31
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optimuslabs/harness-map-staging",
3
- "version": "1.5.39",
3
+ "version": "1.5.40",
4
4
  "description": "CLI helpers for logging hardware UUIDs and posting startup payloads to Optimus Security.",
5
5
  "type": "module",
6
6
  "bin": {