@addai/node 0.8.0 → 0.8.1

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 CHANGED
@@ -1,96 +1,96 @@
1
- # entities-runtime
2
-
3
- A standalone Node.js daemon. Install it on any machine, pair with your
4
- +Ai account, and your account can then run Claude Code / Codex sessions
5
- on that machine on its behalf — from Vault, from Entity Studio, or from
6
- anywhere else in +Ai.
7
-
8
- ## Quick start
9
-
10
- ```bash
11
- npx entities-runtime
12
- ```
13
-
14
- The first run prints a 5-letter pairing code and a URL:
15
-
16
- ```
17
- Pair this runtime with your +Ai account.
18
-
19
- https://vault.add.ai/entity/connect/HDXYC
20
-
21
- Enter this code: HDXYC
22
- ```
23
-
24
- Open the URL while signed into Vault, enter the code, and the runtime
25
- starts polling for work. Capabilities (claude, codex, git, node) are
26
- reported every 30 s.
27
-
28
- ## Commands
29
-
30
- ```
31
- entities-runtime run the daemon (foreground)
32
- entities-runtime status pairing + capabilities + last-seen
33
- entities-runtime sessions recent requests handled (--limit N)
34
- entities-runtime unpair --yes disconnect from +Ai
35
- entities-runtime version print version
36
- ```
37
-
38
- `status` and `sessions` work without the daemon running — they hit
39
- Supabase directly using the daemon token in
40
- `~/.entities-runtime/state.json`.
41
-
42
- ## Architecture
43
-
44
- See [`docs/architecture.md`](docs/architecture.md) for the full picture:
45
- Supabase tables, RPC inventory, request lifecycle, and the cancel-watcher
46
- flow.
47
-
48
- ## DiskGuard — Codex scratch-dir disk protection
49
-
50
- Each Codex run gets a throwaway `CODEX_HOME` under the OS temp dir
51
- (`entities-codex-<rand>`). Codex writes its `state_*.sqlite`, logs, caches
52
- and shell snapshots there — typically 50–350 MB per run. codex-spawn now
53
- deletes that dir on exit, but a `SIGKILL`, a crash, or an orphan left by a
54
- previous runtime process can skip that path. On a dedicated host doing
55
- thousands of runs, those leftovers once grew to ~158 GiB and filled the
56
- disk (`ENOSPC`, repeated crashes).
57
-
58
- **DiskGuard** is the safety net. Like a CCTV DVR overwriting the oldest
59
- footage when the disk fills, it watches free space on the volume holding
60
- the temp dir and, when usage crosses a high-water mark, deletes the
61
- **oldest inactive** scratch dirs — oldest first — until usage drops back
62
- below a low-water mark, leaving a buffer for the OS. It runs at startup, on
63
- an interval, and opportunistically right before each new Codex run.
64
-
65
- Safety guarantees: it only touches directories directly under the temp root
66
- whose names match the configured prefix (realpath-validated); it never
67
- deletes a dir owned by a live session (in-process, or one whose
68
- `session.lock` PID is still alive) or one younger than the min-age guard;
69
- and it removes symlink *entries* without following them, so the durable
70
- `~/.codex` targets behind `sessions`/`auth.json` are never harmed.
71
-
72
- Note: DiskGuard can only reclaim space by deleting scratch dirs it owns. If
73
- a disk is full of *other* data it will evict what it can and log that it
74
- couldn't reach the target rather than touching anything it doesn't own.
75
-
76
- Configure via environment variables (defaults shown):
77
-
78
- | Variable | Default | Meaning |
79
- |---|---|---|
80
- | `DISKGUARD_ENABLED` | `true` | Master switch for the sweeper. Cleanup-on-exit still runs when `false`. |
81
- | `DISKGUARD_HIGH_WATER_PCT` | `90` | Start evicting when volume usage reaches this %. |
82
- | `DISKGUARD_LOW_WATER_PCT` | `80` | Stop evicting once usage drops below this %. Clamped below high-water. |
83
- | `DISKGUARD_MIN_AGE_MINUTES` | `30` | Never evict a scratch dir younger than this. |
84
- | `DISKGUARD_CHECK_INTERVAL_SECONDS` | `60` | Periodic sweep cadence. |
85
- | `DISKGUARD_DRY_RUN` | `false` | Log what would be evicted without deleting anything. |
86
- | `DISKGUARD_PREFIXES` | `entities-codex-` | Comma-separated dir-name prefixes eligible for eviction. |
87
- | `DISKGUARD_TEMP_ROOT` | `os.tmpdir()` | Override the watched temp root (mainly for testing). |
88
-
89
- ## Development
90
-
91
- ```bash
92
- npm install
93
- npm run build
94
- node dist/cli.js
95
- npm test # builds, then runs the node:test suite (see test/)
96
- ```
1
+ # entities-runtime
2
+
3
+ A standalone Node.js daemon. Install it on any machine, pair with your
4
+ +Ai account, and your account can then run Claude Code / Codex sessions
5
+ on that machine on its behalf — from Vault, from Entity Studio, or from
6
+ anywhere else in +Ai.
7
+
8
+ ## Quick start
9
+
10
+ ```bash
11
+ npx entities-runtime
12
+ ```
13
+
14
+ The first run prints a 5-letter pairing code and a URL:
15
+
16
+ ```
17
+ Pair this runtime with your +Ai account.
18
+
19
+ https://vault.add.ai/entity/connect/HDXYC
20
+
21
+ Enter this code: HDXYC
22
+ ```
23
+
24
+ Open the URL while signed into Vault, enter the code, and the runtime
25
+ starts polling for work. Capabilities (claude, codex, git, node) are
26
+ reported every 30 s.
27
+
28
+ ## Commands
29
+
30
+ ```
31
+ entities-runtime run the daemon (foreground)
32
+ entities-runtime status pairing + capabilities + last-seen
33
+ entities-runtime sessions recent requests handled (--limit N)
34
+ entities-runtime unpair --yes disconnect from +Ai
35
+ entities-runtime version print version
36
+ ```
37
+
38
+ `status` and `sessions` work without the daemon running — they hit
39
+ Supabase directly using the daemon token in
40
+ `~/.entities-runtime/state.json`.
41
+
42
+ ## Architecture
43
+
44
+ See [`docs/architecture.md`](docs/architecture.md) for the full picture:
45
+ Supabase tables, RPC inventory, request lifecycle, and the cancel-watcher
46
+ flow.
47
+
48
+ ## DiskGuard — Codex scratch-dir disk protection
49
+
50
+ Each Codex run gets a throwaway `CODEX_HOME` under the OS temp dir
51
+ (`entities-codex-<rand>`). Codex writes its `state_*.sqlite`, logs, caches
52
+ and shell snapshots there — typically 50–350 MB per run. codex-spawn now
53
+ deletes that dir on exit, but a `SIGKILL`, a crash, or an orphan left by a
54
+ previous runtime process can skip that path. On a dedicated host doing
55
+ thousands of runs, those leftovers once grew to ~158 GiB and filled the
56
+ disk (`ENOSPC`, repeated crashes).
57
+
58
+ **DiskGuard** is the safety net. Like a CCTV DVR overwriting the oldest
59
+ footage when the disk fills, it watches free space on the volume holding
60
+ the temp dir and, when usage crosses a high-water mark, deletes the
61
+ **oldest inactive** scratch dirs — oldest first — until usage drops back
62
+ below a low-water mark, leaving a buffer for the OS. It runs at startup, on
63
+ an interval, and opportunistically right before each new Codex run.
64
+
65
+ Safety guarantees: it only touches directories directly under the temp root
66
+ whose names match the configured prefix (realpath-validated); it never
67
+ deletes a dir owned by a live session (in-process, or one whose
68
+ `session.lock` PID is still alive) or one younger than the min-age guard;
69
+ and it removes symlink *entries* without following them, so the durable
70
+ `~/.codex` targets behind `sessions`/`auth.json` are never harmed.
71
+
72
+ Note: DiskGuard can only reclaim space by deleting scratch dirs it owns. If
73
+ a disk is full of *other* data it will evict what it can and log that it
74
+ couldn't reach the target rather than touching anything it doesn't own.
75
+
76
+ Configure via environment variables (defaults shown):
77
+
78
+ | Variable | Default | Meaning |
79
+ |---|---|---|
80
+ | `DISKGUARD_ENABLED` | `true` | Master switch for the sweeper. Cleanup-on-exit still runs when `false`. |
81
+ | `DISKGUARD_HIGH_WATER_PCT` | `90` | Start evicting when volume usage reaches this %. |
82
+ | `DISKGUARD_LOW_WATER_PCT` | `80` | Stop evicting once usage drops below this %. Clamped below high-water. |
83
+ | `DISKGUARD_MIN_AGE_MINUTES` | `30` | Never evict a scratch dir younger than this. |
84
+ | `DISKGUARD_CHECK_INTERVAL_SECONDS` | `60` | Periodic sweep cadence. |
85
+ | `DISKGUARD_DRY_RUN` | `false` | Log what would be evicted without deleting anything. |
86
+ | `DISKGUARD_PREFIXES` | `entities-codex-` | Comma-separated dir-name prefixes eligible for eviction. |
87
+ | `DISKGUARD_TEMP_ROOT` | `os.tmpdir()` | Override the watched temp root (mainly for testing). |
88
+
89
+ ## Development
90
+
91
+ ```bash
92
+ npm install
93
+ npm run build
94
+ node dist/cli.js
95
+ npm test # builds, then runs the node:test suite (see test/)
96
+ ```
@@ -79,36 +79,36 @@ function buildPlist(spec) {
79
79
  const env = Object.entries(spec.env)
80
80
  .map(([k, v]) => ` <key>${esc(k)}</key>\n <string>${esc(v)}</string>`)
81
81
  .join('\n');
82
- return `<?xml version="1.0" encoding="UTF-8"?>
83
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
84
- <plist version="1.0">
85
- <dict>
86
- <key>Label</key>
87
- <string>${esc(spec.label)}</string>
88
- <key>ProgramArguments</key>
89
- <array>
90
- ${args}
91
- </array>
92
- <key>RunAtLoad</key>
93
- <true/>
94
- <key>KeepAlive</key>
95
- <true/>
96
- <key>ThrottleInterval</key>
97
- <integer>10</integer>
98
- <key>ProcessType</key>
99
- <string>Interactive</string>
100
- <key>WorkingDirectory</key>
101
- <string>${esc(spec.workingDirectory)}</string>
102
- <key>StandardOutPath</key>
103
- <string>${esc(spec.logPath)}</string>
104
- <key>StandardErrorPath</key>
105
- <string>${esc(spec.logPath)}</string>
106
- <key>EnvironmentVariables</key>
107
- <dict>
108
- ${env}
109
- </dict>
110
- </dict>
111
- </plist>
82
+ return `<?xml version="1.0" encoding="UTF-8"?>
83
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
84
+ <plist version="1.0">
85
+ <dict>
86
+ <key>Label</key>
87
+ <string>${esc(spec.label)}</string>
88
+ <key>ProgramArguments</key>
89
+ <array>
90
+ ${args}
91
+ </array>
92
+ <key>RunAtLoad</key>
93
+ <true/>
94
+ <key>KeepAlive</key>
95
+ <true/>
96
+ <key>ThrottleInterval</key>
97
+ <integer>10</integer>
98
+ <key>ProcessType</key>
99
+ <string>Interactive</string>
100
+ <key>WorkingDirectory</key>
101
+ <string>${esc(spec.workingDirectory)}</string>
102
+ <key>StandardOutPath</key>
103
+ <string>${esc(spec.logPath)}</string>
104
+ <key>StandardErrorPath</key>
105
+ <string>${esc(spec.logPath)}</string>
106
+ <key>EnvironmentVariables</key>
107
+ <dict>
108
+ ${env}
109
+ </dict>
110
+ </dict>
111
+ </plist>
112
112
  `;
113
113
  }
114
114
  /** Pull ProgramArguments back out of a plist we wrote, for `status`. */
@@ -128,56 +128,56 @@ function buildVbs(cmdPath) {
128
128
  * a second daemon.
129
129
  */
130
130
  function buildTaskXml(spec) {
131
- return `<?xml version="1.0" encoding="UTF-16"?>
132
- <Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
133
- <RegistrationInfo>
134
- <Date>${xmlEsc(spec.createdAt)}</Date>
135
- <Author>@addai/node</Author>
136
- <Description>Runs this +Ai Node so entities can reach it. Created by \`ainode startup enable\`.</Description>
137
- </RegistrationInfo>
138
- <Triggers>
139
- <LogonTrigger>
140
- <Enabled>true</Enabled>
141
- <UserId>${xmlEsc(spec.userId)}</UserId>
142
- <Repetition>
143
- <Interval>PT5M</Interval>
144
- <StopAtDurationEnd>false</StopAtDurationEnd>
145
- </Repetition>
146
- </LogonTrigger>
147
- </Triggers>
148
- <Principals>
149
- <Principal id="Author">
150
- <UserId>${xmlEsc(spec.userId)}</UserId>
151
- <LogonType>InteractiveToken</LogonType>
152
- <RunLevel>LeastPrivilege</RunLevel>
153
- </Principal>
154
- </Principals>
155
- <Settings>
156
- <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
157
- <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
158
- <StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>
159
- <AllowHardTerminate>true</AllowHardTerminate>
160
- <StartWhenAvailable>true</StartWhenAvailable>
161
- <RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
162
- <IdleSettings>
163
- <StopOnIdleEnd>false</StopOnIdleEnd>
164
- <RestartOnIdle>false</RestartOnIdle>
165
- </IdleSettings>
166
- <AllowStartOnDemand>true</AllowStartOnDemand>
167
- <Enabled>true</Enabled>
168
- <Hidden>false</Hidden>
169
- <RunOnlyIfIdle>false</RunOnlyIfIdle>
170
- <WakeToRun>false</WakeToRun>
171
- <ExecutionTimeLimit>PT0S</ExecutionTimeLimit>
172
- <Priority>7</Priority>
173
- </Settings>
174
- <Actions Context="Author">
175
- <Exec>
176
- <Command>${xmlEsc(spec.wscriptPath)}</Command>
177
- <Arguments>"${xmlEsc(spec.vbsPath)}"</Arguments>
178
- </Exec>
179
- </Actions>
180
- </Task>
131
+ return `<?xml version="1.0" encoding="UTF-16"?>
132
+ <Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
133
+ <RegistrationInfo>
134
+ <Date>${xmlEsc(spec.createdAt)}</Date>
135
+ <Author>@addai/node</Author>
136
+ <Description>Runs this +Ai Node so entities can reach it. Created by \`ainode startup enable\`.</Description>
137
+ </RegistrationInfo>
138
+ <Triggers>
139
+ <LogonTrigger>
140
+ <Enabled>true</Enabled>
141
+ <UserId>${xmlEsc(spec.userId)}</UserId>
142
+ <Repetition>
143
+ <Interval>PT5M</Interval>
144
+ <StopAtDurationEnd>false</StopAtDurationEnd>
145
+ </Repetition>
146
+ </LogonTrigger>
147
+ </Triggers>
148
+ <Principals>
149
+ <Principal id="Author">
150
+ <UserId>${xmlEsc(spec.userId)}</UserId>
151
+ <LogonType>InteractiveToken</LogonType>
152
+ <RunLevel>LeastPrivilege</RunLevel>
153
+ </Principal>
154
+ </Principals>
155
+ <Settings>
156
+ <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
157
+ <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
158
+ <StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>
159
+ <AllowHardTerminate>true</AllowHardTerminate>
160
+ <StartWhenAvailable>true</StartWhenAvailable>
161
+ <RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
162
+ <IdleSettings>
163
+ <StopOnIdleEnd>false</StopOnIdleEnd>
164
+ <RestartOnIdle>false</RestartOnIdle>
165
+ </IdleSettings>
166
+ <AllowStartOnDemand>true</AllowStartOnDemand>
167
+ <Enabled>true</Enabled>
168
+ <Hidden>false</Hidden>
169
+ <RunOnlyIfIdle>false</RunOnlyIfIdle>
170
+ <WakeToRun>false</WakeToRun>
171
+ <ExecutionTimeLimit>PT0S</ExecutionTimeLimit>
172
+ <Priority>7</Priority>
173
+ </Settings>
174
+ <Actions Context="Author">
175
+ <Exec>
176
+ <Command>${xmlEsc(spec.wscriptPath)}</Command>
177
+ <Arguments>"${xmlEsc(spec.vbsPath)}"</Arguments>
178
+ </Exec>
179
+ </Actions>
180
+ </Task>
181
181
  `;
182
182
  }
183
183
  function schtasks(args) {
package/dist/cli.js CHANGED
@@ -192,23 +192,23 @@ async function main() {
192
192
  case 'help':
193
193
  case '--help':
194
194
  case '-h':
195
- console.log(`ainode v${index_1.VERSION}
196
-
197
- usage:
198
- ainode run this +Ai Node — daemon + live dashboard
199
- ainode harnesses install / log in agent harnesses (interactive)
200
- ainode startup enable start this node whenever you log in
201
- ainode startup disable stop starting at login
202
- ainode startup status where the startup entry is and what it runs
203
- ainode unpair --yes disconnect from +Ai
204
- ainode version print version
205
-
206
- Piped or headless output falls back to plain log lines. Set AINODE_NO_TUI=1
207
- to force that on a terminal. \`ainode run --ensure\` starts a node only if one
208
- isn't already running — what the Windows startup task uses.
209
-
210
- Pair the node by running it with no args and following the prompt
211
- to vault.add.ai/entity/connect/<CODE>.
195
+ console.log(`ainode v${index_1.VERSION}
196
+
197
+ usage:
198
+ ainode run this +Ai Node — daemon + live dashboard
199
+ ainode harnesses install / log in agent harnesses (interactive)
200
+ ainode startup enable start this node whenever you log in
201
+ ainode startup disable stop starting at login
202
+ ainode startup status where the startup entry is and what it runs
203
+ ainode unpair --yes disconnect from +Ai
204
+ ainode version print version
205
+
206
+ Piped or headless output falls back to plain log lines. Set AINODE_NO_TUI=1
207
+ to force that on a terminal. \`ainode run --ensure\` starts a node only if one
208
+ isn't already running — what the Windows startup task uses.
209
+
210
+ Pair the node by running it with no args and following the prompt
211
+ to vault.add.ai/entity/connect/<CODE>.
212
212
  `);
213
213
  return;
214
214
  }
@@ -2198,6 +2198,21 @@ async function runRequest(req) {
2198
2198
  catch {
2199
2199
  /* drive manifest is best-effort — never block a run */
2200
2200
  }
2201
+ // Living Presence: entities that carry the entity-self MCP narrate their work on
2202
+ // table records via its `report_status` tool. Injected HERE — the one place every
2203
+ // spawn path reads (req.system_prompt) — so it reaches EVERY session, board and
2204
+ // channel from a single source, never per-board. Gated on the tool actually being
2205
+ // installed, so it can't confuse entities that don't have it.
2206
+ if (installed.mcps?.some((m) => m.slug === 'entity-self-mcp')) {
2207
+ const livingPresence = [
2208
+ 'LIVING PRESENCE — narrate your work so people can see what you are doing in real time.',
2209
+ 'Whenever you are working on a specific table record (a card / task / row), call the `report_status` tool at your real milestones: when you claim/start it (status "working", a low progress, a short human note like "Reviewing"), at each checkpoint (bump progress + update the note), if you get stuck and need a human (status "blocked", note why), and when you finish (status "done"). ALWAYS pass the record_id you are working on; if you are working on several records at once, report each separately with its own record_id so they never overwrite each other. This is lightweight — a handful of milestone updates per task; progress is a rough milestone percent (0-100), not a precise measurement.',
2210
+ ].join('\n');
2211
+ req.system_prompt =
2212
+ req.system_prompt && req.system_prompt.trim().length > 0
2213
+ ? `${req.system_prompt}\n\n${livingPresence}`
2214
+ : livingPresence;
2215
+ }
2201
2216
  // Same for the entity's long-term memory: try the +Ai Memory semantic pack
2202
2217
  // (T6's entity-memory-pack edge function) first — it replaces the flat
2203
2218
  // DocFlows title list with a curated recall block for memory_v2-flagged
package/package.json CHANGED
@@ -1,60 +1,60 @@
1
- {
2
- "name": "@addai/node",
3
- "version": "0.8.0",
4
- "description": "Daemon that pairs a machine with your +Ai account and runs Claude / Codex / Kimi / Gemini agents on its behalf. Reachable via Supabase from Vault, Entity Studio, or any other +Ai surface.",
5
- "license": "MIT",
6
- "keywords": [
7
- "addai",
8
- "entity-studio",
9
- "claude",
10
- "codex",
11
- "kimi",
12
- "gemini",
13
- "agent",
14
- "daemon",
15
- "supabase",
16
- "mcp"
17
- ],
18
- "repository": {
19
- "type": "git",
20
- "url": "git+https://github.com/just-AddAi/addai-entity-runtime.git"
21
- },
22
- "homepage": "https://github.com/just-AddAi/addai-entity-runtime#readme",
23
- "bugs": {
24
- "url": "https://github.com/just-AddAi/addai-entity-runtime/issues"
25
- },
26
- "type": "commonjs",
27
- "main": "dist/index.js",
28
- "bin": {
29
- "ainode": "dist/cli.js"
30
- },
31
- "publishConfig": {
32
- "access": "public"
33
- },
34
- "files": [
35
- "dist",
36
- "scripts",
37
- "README.md"
38
- ],
39
- "scripts": {
40
- "build": "tsc -p tsconfig.json",
41
- "start": "node dist/cli.js",
42
- "dev": "tsc -p tsconfig.json && node dist/cli.js",
43
- "test": "npm run build && node --test test/*.test.mjs",
44
- "clean": "node -e \"fs.rmSync('dist',{recursive:true,force:true})\"",
45
- "postinstall": "node scripts/fix-pty-helper.js",
46
- "prepublishOnly": "npm run build"
47
- },
48
- "engines": {
49
- "node": ">=18"
50
- },
51
- "dependencies": {
52
- "node-pty": "^1.1.0",
53
- "ws": "^8.21.1"
54
- },
55
- "devDependencies": {
56
- "@types/node": "^20.0.0",
57
- "@types/ws": "^8.18.1",
58
- "typescript": "^5.6.0"
59
- }
60
- }
1
+ {
2
+ "name": "@addai/node",
3
+ "version": "0.8.1",
4
+ "description": "Daemon that pairs a machine with your +Ai account and runs Claude / Codex / Kimi / Gemini agents on its behalf. Reachable via Supabase from Vault, Entity Studio, or any other +Ai surface.",
5
+ "license": "MIT",
6
+ "keywords": [
7
+ "addai",
8
+ "entity-studio",
9
+ "claude",
10
+ "codex",
11
+ "kimi",
12
+ "gemini",
13
+ "agent",
14
+ "daemon",
15
+ "supabase",
16
+ "mcp"
17
+ ],
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/just-AddAi/addai-entity-runtime.git"
21
+ },
22
+ "homepage": "https://github.com/just-AddAi/addai-entity-runtime#readme",
23
+ "bugs": {
24
+ "url": "https://github.com/just-AddAi/addai-entity-runtime/issues"
25
+ },
26
+ "type": "commonjs",
27
+ "main": "dist/index.js",
28
+ "bin": {
29
+ "ainode": "dist/cli.js"
30
+ },
31
+ "publishConfig": {
32
+ "access": "public"
33
+ },
34
+ "files": [
35
+ "dist",
36
+ "scripts",
37
+ "README.md"
38
+ ],
39
+ "scripts": {
40
+ "build": "tsc -p tsconfig.json",
41
+ "start": "node dist/cli.js",
42
+ "dev": "tsc -p tsconfig.json && node dist/cli.js",
43
+ "test": "npm run build && node --test test/*.test.mjs",
44
+ "clean": "node -e \"fs.rmSync('dist',{recursive:true,force:true})\"",
45
+ "postinstall": "node scripts/fix-pty-helper.js",
46
+ "prepublishOnly": "npm run build"
47
+ },
48
+ "engines": {
49
+ "node": ">=18"
50
+ },
51
+ "dependencies": {
52
+ "node-pty": "^1.1.0",
53
+ "ws": "^8.21.1"
54
+ },
55
+ "devDependencies": {
56
+ "@types/node": "^20.0.0",
57
+ "@types/ws": "^8.18.1",
58
+ "typescript": "^5.6.0"
59
+ }
60
+ }
@@ -1,28 +1,28 @@
1
- #!/usr/bin/env node
2
- // node-pty ships POSIX prebuilds whose `spawn-helper` binary can lose its
3
- // executable bit when the npm tarball is extracted. macOS node-pty
4
- // posix_spawn()s that helper, so without +x every PTY spawn dies with
5
- // "posix_spawnp failed." — see src/pty-helper.ts for the full story.
6
- //
7
- // This used to hunt for <pkg>/node_modules/node-pty by hand, a path that
8
- // only exists when node-pty is NESTED. npm hoists it to the tree root under
9
- // npx, so the fix silently did nothing on exactly the installs that needed
10
- // it. The real logic now lives in the daemon (dist/pty-helper.js) and
11
- // resolves the package the way Node does. The daemon also repairs at boot,
12
- // so if dist isn't built yet (a source checkout installing before its first
13
- // build) we exit quietly instead of duplicating the logic here.
14
-
15
- let mod;
16
- try {
17
- mod = require('../dist/pty-helper.js');
18
- } catch {
19
- process.exit(0);
20
- }
21
-
22
- try {
23
- const line = mod.describeRepair(mod.ensurePtyHelperExecutable());
24
- if (line) process.stdout.write(`[entities-runtime] ${line}\n`);
25
- } catch (err) {
26
- process.stderr.write(`[entities-runtime] pty helper check failed: ${err.message}\n`);
27
- }
28
- process.exit(0);
1
+ #!/usr/bin/env node
2
+ // node-pty ships POSIX prebuilds whose `spawn-helper` binary can lose its
3
+ // executable bit when the npm tarball is extracted. macOS node-pty
4
+ // posix_spawn()s that helper, so without +x every PTY spawn dies with
5
+ // "posix_spawnp failed." — see src/pty-helper.ts for the full story.
6
+ //
7
+ // This used to hunt for <pkg>/node_modules/node-pty by hand, a path that
8
+ // only exists when node-pty is NESTED. npm hoists it to the tree root under
9
+ // npx, so the fix silently did nothing on exactly the installs that needed
10
+ // it. The real logic now lives in the daemon (dist/pty-helper.js) and
11
+ // resolves the package the way Node does. The daemon also repairs at boot,
12
+ // so if dist isn't built yet (a source checkout installing before its first
13
+ // build) we exit quietly instead of duplicating the logic here.
14
+
15
+ let mod;
16
+ try {
17
+ mod = require('../dist/pty-helper.js');
18
+ } catch {
19
+ process.exit(0);
20
+ }
21
+
22
+ try {
23
+ const line = mod.describeRepair(mod.ensurePtyHelperExecutable());
24
+ if (line) process.stdout.write(`[entities-runtime] ${line}\n`);
25
+ } catch (err) {
26
+ process.stderr.write(`[entities-runtime] pty helper check failed: ${err.message}\n`);
27
+ }
28
+ process.exit(0);