@intentic/constants 1.370.0 → 1.371.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentic/constants",
3
- "version": "1.370.0",
3
+ "version": "1.371.0",
4
4
  "description": "Shared constants for the intentic packages, ports, paths, and image references the daemon, CLIs and desktop app all agree on",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -31,6 +31,7 @@ export const TOUCH_EVERY_MS: number;
31
31
  export function previewsDir(env?: Readonly<Record<string, string | undefined>>): string;
32
32
  export function recordName(conversation: string, label: string): string;
33
33
  export function recordPath(dir: string, conversation: string, label: string): string;
34
+ export function openPreviewLog(dir: string, conversation: string, label: string): { readonly path: string; readonly fd: number };
34
35
  export function hostLabel(conversation: string): string;
35
36
  export function startTicksOf(pid: number, procRoot?: string): string | undefined;
36
37
  export function ownerOf(pid: number, procRoot?: string): string | undefined;
@@ -10,7 +10,7 @@
10
10
  // alive, must have started at the clock tick the record says (a reused pid fails that), and must carry the
11
11
  // conversation stamp (INTENTIC_TURN_OWNER) the record claims. A record written from another pid namespace (an agent
12
12
  // domain has its own) names a pid this reader cannot see, so it is neither trusted nor removed here.
13
- import { chmodSync, mkdirSync, readdirSync, readFileSync, readlinkSync, renameSync, rmSync, writeFileSync } from "node:fs";
13
+ import { chmodSync, mkdirSync, mkdtempSync, openSync, readdirSync, readFileSync, readlinkSync, renameSync, rmSync, writeFileSync } from "node:fs";
14
14
  import { createServer } from "node:net";
15
15
  import { join } from "node:path";
16
16
 
@@ -45,13 +45,27 @@ export const recordPath = (dir, conversation, label) => join(dir, `${recordName(
45
45
  const stopPath = (dir, conversation, label) => join(dir, `${recordName(conversation, label)}${STOP_SUFFIX}`);
46
46
  const endedPath = (dir, conversation, label) => join(dir, `${recordName(conversation, label)}${ENDED_SUFFIX}`);
47
47
 
48
+ // A restart replaces the old directory entry, then creates exclusively: a pre-planted symlink or hard link never
49
+ // opens its target for truncation. A concurrent creator makes the open fail instead of following its entry.
50
+ export const openPreviewLog = (dir, conversation, label) => {
51
+ mkdirSync(dir, { recursive: true });
52
+ const path = join(dir, `${recordName(conversation, label)}.log`);
53
+ rmSync(path, { force: true });
54
+ return { path, fd: openSync(path, "wx") };
55
+ };
56
+
48
57
  // A conversation id as one DNS label, for its preview's hostname: `<label>.demo.localhost`.
49
- export const hostLabel = (conversation) =>
50
- conversation
58
+ export const hostLabel = (conversation) => {
59
+ const label = conversation
51
60
  .toLowerCase()
52
61
  .replaceAll(/[^a-z0-9-]+/gu, "-")
53
- .replaceAll(/^-+|-+$/gu, "")
54
- .slice(0, 63) || "preview";
62
+ .replace(/^-+/u, "");
63
+ let end = label.length;
64
+ while (label.charAt(end - 1) === "-") {
65
+ end -= 1;
66
+ }
67
+ return label.slice(0, Math.min(end, 63)) || "preview";
68
+ };
55
69
 
56
70
  // Field 22 of /proc/<pid>/stat, the process's start time in clock ticks since boot. The command name (field 2) can
57
71
  // hold spaces and parentheses, so fields are counted after its closing parenthesis.
@@ -135,9 +149,14 @@ export const recordIsLive = (record, procRoot = "/proc") =>
135
149
 
136
150
  // Written whole and renamed into place, so a reader never sees half a file.
137
151
  const writeWhole = (path, text) => {
138
- const temporary = `${path}.${String(process.pid)}.tmp`;
139
- writeFileSync(temporary, text);
140
- renameSync(temporary, path);
152
+ const staging = mkdtempSync(`${path}.`);
153
+ try {
154
+ const temporary = join(staging, "record");
155
+ writeFileSync(temporary, text, { flag: "wx" });
156
+ renameSync(temporary, path);
157
+ } finally {
158
+ rmSync(staging, { recursive: true, force: true });
159
+ }
141
160
  };
142
161
 
143
162
  // A dead record's stop note becomes its ended note: why it stopped, kept for the next start or listing to say.