@justfortytwo/installer 1.0.0-10 → 1.0.0-11
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 +43 -1
- package/dist/commands/stop.d.ts.map +1 -1
- package/dist/commands/stop.js +7 -4
- package/dist/commands/stop.js.map +1 -1
- package/dist/process-identity.d.ts +3 -0
- package/dist/process-identity.d.ts.map +1 -0
- package/dist/process-identity.js +42 -0
- package/dist/process-identity.js.map +1 -0
- package/dist/runtime.d.ts +5 -1
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +17 -5
- package/dist/runtime.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -86,7 +86,7 @@ gitignored `.fortytwo/identity.json`; neither is ever committed.
|
|
|
86
86
|
|------------|--------------|
|
|
87
87
|
| `start` | Run fortytwo in the foreground: load the project `.env` (the shell/container env wins over it), start every installed and configured service (the Telegram bridge needs `TELEGRAM_BOT_TOKEN`; the scheduler daemon needs nothing), prefix and forward their logs, and stop them all on Ctrl+C/SIGTERM. If a service exits, the others are stopped and `start` exits non-zero. It never daemonizes or restarts anything — see [Running as a service](#running-as-a-service). |
|
|
88
88
|
| `status` | Show whether fortytwo, the Telegram bridge and the scheduler are running, and whether memory is configured. Exits 0 when `fortytwo start` is running, 3 when not (usable as a health check). |
|
|
89
|
-
| `stop` | Stop the `fortytwo start` running for this project. It signals only the process recorded in `.fortytwo/runtime.json`, and only while that record's heartbeat is fresh; it never looks for processes by name. |
|
|
89
|
+
| `stop` | Stop the `fortytwo start` running for this project. It signals only the process recorded in `.fortytwo/runtime.json`, and only while that record's heartbeat is fresh and its OS process-start identity matches; it never looks for processes by name. |
|
|
90
90
|
| `init` | Install any missing engine packages, pin this CLI into the project and install the `fortytwo` launcher (see [The `fortytwo` command](#the-fortytwo-command)), then capture your assistant's name + owner details (interactive, or via flags/env for CI). Writes `.fortytwo/identity.json`, secrets + `ALLOWED_CHAT_IDS` to `.env`, wires `.mcp.json`, renders the persona, provisions local infra (pulls the embedder model, migrates the memory DB), and records the installed version set. |
|
|
91
91
|
| `pair` | Issue a one-time `/login` pairing code, persisted to the bridge's bindings db so the running bridge can redeem it (the dynamic counterpart to the static `ALLOWED_CHAT_IDS` allowlist). Refuses, and tells you to run `fortytwo start`, when Telegram isn't running; `--force` issues a code anyway (for a bridge you run yourself). |
|
|
92
92
|
| `doctor` | Health-check the engine: assert the gate's `POLICY_SCHEMA_VERSION` and memory's `MEMORY_TOOL_CONTRACT_VERSION` match what this CLI expects, confirm the memory DB is migrated, cross-check installed sibling versions against the declared compatibility ranges, and check the embedder model is pulled (warn-only). |
|
|
@@ -245,3 +245,45 @@ coordinated versions are released, use the new CLI, stop services with
|
|
|
245
245
|
`fortytwo stop` (or the service manager), run `fortytwo update`, then restart via
|
|
246
246
|
`fortytwo start`. Update refuses live services before changing anything so an
|
|
247
247
|
old scheduler cannot claim jobs it does not understand. No second init is needed.
|
|
248
|
+
|
|
249
|
+
### Runtime ownership across container restarts
|
|
250
|
+
|
|
251
|
+
`runtime.json` records `processIdentity` alongside the supervisor PID and
|
|
252
|
+
heartbeat. On Linux it combines the kernel boot ID, PID namespace and field 22
|
|
253
|
+
(start ticks) of `/proc/<pid>/stat`. A fresh file from an earlier container cannot
|
|
254
|
+
claim a new process merely because its PID was reused. Start, status, pair and
|
|
255
|
+
update use the same ownership check; stop also rechecks immediately before
|
|
256
|
+
signalling and while waiting for that process generation to exit.
|
|
257
|
+
|
|
258
|
+
On macOS and other systems with `ps -p <pid> -o lstart=`, the fallback compares
|
|
259
|
+
the OS start timestamp using a fixed locale/timezone and a bounded command.
|
|
260
|
+
This fallback has second-level precision; it cannot distinguish reuse of the
|
|
261
|
+
same PID within the same second. Linux uses kernel start ticks instead. Missing
|
|
262
|
+
or unreadable identity is never accepted as proof of ownership, and a supervisor
|
|
263
|
+
that cannot read its own identity refuses to start services.
|
|
264
|
+
|
|
265
|
+
Legacy runtime records without `processIdentity` are treated as stale. Stop an
|
|
266
|
+
older running supervisor through its container/service manager before upgrading;
|
|
267
|
+
its PID-only record cannot safely be adopted or signalled by the new CLI. The
|
|
268
|
+
heartbeat timeout, foreground supervision and external restart policy are unchanged.
|
|
269
|
+
|
|
270
|
+
Identity is rechecked immediately before `SIGTERM`, but Node's PID-based signal
|
|
271
|
+
API does not make the check and signal atomic. Eliminating that final OS race
|
|
272
|
+
would require a native process handle (for example Linux pidfd), beyond this fix.
|
|
273
|
+
|
|
274
|
+
To reproduce the two-container ownership regression locally (Docker and a
|
|
275
|
+
`node:22` image required), run from the installer repository. Both containers
|
|
276
|
+
use PID 1 and share only the disposable workspace. The repository is read-only.
|
|
277
|
+
The subshell keeps fail-fast settings out of your interactive shell.
|
|
278
|
+
|
|
279
|
+
```sh
|
|
280
|
+
(
|
|
281
|
+
set -euo pipefail
|
|
282
|
+
npm run build
|
|
283
|
+
fixture_dir="$(mktemp -d)"
|
|
284
|
+
docker run --rm -v "$PWD":/code:ro -v "$fixture_dir":/workspace -w /workspace \
|
|
285
|
+
node:22 node /code/test/runtime-container.mjs seed
|
|
286
|
+
docker run --rm -v "$PWD":/code:ro -v "$fixture_dir":/workspace -w /workspace \
|
|
287
|
+
node:22 node /code/test/runtime-container.mjs check
|
|
288
|
+
)
|
|
289
|
+
```
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stop.d.ts","sourceRoot":"","sources":["../../src/commands/stop.ts"],"names":[],"mappings":"AAWA,wBAAsB,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,IAAI,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"stop.d.ts","sourceRoot":"","sources":["../../src/commands/stop.ts"],"names":[],"mappings":"AAWA,wBAAsB,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,IAAI,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAyBjG"}
|
package/dist/commands/stop.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// stop — stop a `fortytwo start` running for this project.
|
|
2
2
|
//
|
|
3
3
|
// Signals ONLY the supervisor recorded in .fortytwo/runtime.json, and only while
|
|
4
|
-
// its heartbeat is fresh (see runtime.ts)
|
|
5
|
-
//
|
|
4
|
+
// its heartbeat is fresh and OS process identity matches (see runtime.ts).
|
|
5
|
+
// It never searches for or kills processes by name. The supervisor
|
|
6
6
|
// then stops its own services. Under Docker/systemd prefer their own stop.
|
|
7
|
-
import {
|
|
7
|
+
import { sameRuntimeProcess, liveRuntime } from '../runtime.js';
|
|
8
8
|
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
9
9
|
export async function runStop(_argv, opts = {}) {
|
|
10
10
|
const runtime = liveRuntime(process.cwd());
|
|
@@ -13,6 +13,9 @@ export async function runStop(_argv, opts = {}) {
|
|
|
13
13
|
return 0;
|
|
14
14
|
}
|
|
15
15
|
process.stdout.write(`Stopping fortytwo (pid ${runtime.pid})…\n`);
|
|
16
|
+
// Revalidate the original generation immediately before signalling.
|
|
17
|
+
if (!sameRuntimeProcess(runtime))
|
|
18
|
+
return 0;
|
|
16
19
|
try {
|
|
17
20
|
process.kill(runtime.pid, 'SIGTERM');
|
|
18
21
|
}
|
|
@@ -22,7 +25,7 @@ export async function runStop(_argv, opts = {}) {
|
|
|
22
25
|
}
|
|
23
26
|
const deadline = Date.now() + (opts.timeoutMs ?? 20_000);
|
|
24
27
|
while (Date.now() < deadline) {
|
|
25
|
-
if (!
|
|
28
|
+
if (!sameRuntimeProcess(runtime)) {
|
|
26
29
|
process.stdout.write('fortytwo stopped.\n');
|
|
27
30
|
return 0;
|
|
28
31
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stop.js","sourceRoot":"","sources":["../../src/commands/stop.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,EAAE;AACF,iFAAiF;AACjF,2EAA2E;AAC3E
|
|
1
|
+
{"version":3,"file":"stop.js","sourceRoot":"","sources":["../../src/commands/stop.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,EAAE;AACF,iFAAiF;AACjF,2EAA2E;AAC3E,mEAAmE;AACnE,2EAA2E;AAE3E,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEhE,MAAM,KAAK,GAAG,CAAC,EAAU,EAAE,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;AAEpE,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,KAAe,EAAE,OAA+B,EAAE;IAC9E,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAC3C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;QACnD,OAAO,CAAC,CAAC;IACX,CAAC;IACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,0BAA0B,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC;IAClE,oEAAoE;IACpE,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC;QAAE,OAAO,CAAC,CAAC;IAC3C,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IACvC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,8BAA8B,OAAO,CAAC,GAAG,KAAM,GAAa,CAAC,OAAO,IAAI,CAAC,CAAC;QAC/F,OAAO,CAAC,CAAC;IACX,CAAC;IACD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,SAAS,IAAI,MAAM,CAAC,CAAC;IACzD,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;QAC7B,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,EAAE,CAAC;YACjC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;YAC5C,OAAO,CAAC,CAAC;QACX,CAAC;QACD,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;IACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,uBAAuB,OAAO,CAAC,GAAG,qCAAqC,CAAC,CAAC;IAC9F,OAAO,CAAC,CAAC;AACX,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process-identity.d.ts","sourceRoot":"","sources":["../src/process-identity.ts"],"names":[],"mappings":"AAIA,mFAAmF;AACnF,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAAG,MAAM,GAAG,IAAI,CA6B5G"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// OS process generation identity, independent of the project's heartbeat.
|
|
2
|
+
import { readFileSync, readlinkSync } from 'node:fs';
|
|
3
|
+
import { spawnSync } from 'node:child_process';
|
|
4
|
+
/** null means identity cannot be established; never fall back to PID existence. */
|
|
5
|
+
export function readProcessIdentity(pid, platform = process.platform) {
|
|
6
|
+
if (!Number.isSafeInteger(pid) || pid <= 0)
|
|
7
|
+
return null;
|
|
8
|
+
try {
|
|
9
|
+
if (platform === 'linux') {
|
|
10
|
+
const stat = readFileSync(`/proc/${pid}/stat`, 'utf8');
|
|
11
|
+
// comm (field 2) is parenthesized, but may itself contain ')' or whitespace.
|
|
12
|
+
const end = stat.lastIndexOf(')');
|
|
13
|
+
if (!stat.startsWith(`${pid} (`) || end < 0)
|
|
14
|
+
return null;
|
|
15
|
+
const fields = stat.slice(end + 1).trim().split(/\s+/);
|
|
16
|
+
const start = fields[19]; // fields[0] is state (field 3); starttime is field 22
|
|
17
|
+
if (!start || !/^\d+$/.test(start) || ['Z', 'X', 'x'].includes(fields[0] ?? ''))
|
|
18
|
+
return null;
|
|
19
|
+
const boot = readFileSync('/proc/sys/kernel/random/boot_id', 'utf8').trim();
|
|
20
|
+
const namespace = readlinkSync(`/proc/${pid}/ns/pid`);
|
|
21
|
+
if (!boot || !/^pid:\[\d+\]$/.test(namespace))
|
|
22
|
+
return null;
|
|
23
|
+
return `linux:${boot}:${namespace}:${start}`;
|
|
24
|
+
}
|
|
25
|
+
// BSD/macOS ps exposes an OS-derived start time (second resolution).
|
|
26
|
+
// Fix locale/timezone so callers with different environments compare equally.
|
|
27
|
+
const result = spawnSync('ps', ['-p', String(pid), '-o', 'lstart='], {
|
|
28
|
+
encoding: 'utf8', timeout: 2000, env: { ...process.env, LC_ALL: 'C', TZ: 'UTC' },
|
|
29
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
30
|
+
});
|
|
31
|
+
if (result.error || result.status !== 0)
|
|
32
|
+
return null;
|
|
33
|
+
const start = result.stdout.trim().replace(/\s+/g, ' ');
|
|
34
|
+
if (!/^[A-Z][a-z]{2} [A-Z][a-z]{2} \d{1,2} \d{2}:\d{2}:\d{2} \d{4}$/.test(start))
|
|
35
|
+
return null;
|
|
36
|
+
return `ps:${platform}:${start}`;
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=process-identity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process-identity.js","sourceRoot":"","sources":["../src/process-identity.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,mFAAmF;AACnF,MAAM,UAAU,mBAAmB,CAAC,GAAW,EAAE,WAA4B,OAAO,CAAC,QAAQ;IAC3F,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACxD,IAAI,CAAC;QACH,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;YACzB,MAAM,IAAI,GAAG,YAAY,CAAC,SAAS,GAAG,OAAO,EAAE,MAAM,CAAC,CAAC;YACvD,6EAA6E;YAC7E,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;YAClC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,GAAG,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC;gBAAE,OAAO,IAAI,CAAC;YACzD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACvD,MAAM,KAAK,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,sDAAsD;YAChF,IAAI,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;gBAAE,OAAO,IAAI,CAAC;YAC7F,MAAM,IAAI,GAAG,YAAY,CAAC,iCAAiC,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;YAC5E,MAAM,SAAS,GAAG,YAAY,CAAC,SAAS,GAAG,SAAS,CAAC,CAAC;YACtD,IAAI,CAAC,IAAI,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,SAAS,CAAC;gBAAE,OAAO,IAAI,CAAC;YAC3D,OAAO,SAAS,IAAI,IAAI,SAAS,IAAI,KAAK,EAAE,CAAC;QAC/C,CAAC;QACD,qEAAqE;QACrE,8EAA8E;QAC9E,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,EAAE;YACnE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE;YAChF,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC;SACpC,CAAC,CAAC;QACH,IAAI,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QACrD,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QACxD,IAAI,CAAC,+DAA+D,CAAC,IAAI,CAAC,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAC9F,OAAO,MAAM,QAAQ,IAAI,KAAK,EAAE,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
|
package/dist/runtime.d.ts
CHANGED
|
@@ -33,6 +33,8 @@ export declare function planServices(root: string, env: NodeJS.ProcessEnv, specs
|
|
|
33
33
|
export interface RuntimeState {
|
|
34
34
|
/** The `fortytwo start` supervisor process. */
|
|
35
35
|
pid: number;
|
|
36
|
+
/** OS process generation; absent in legacy records, which are not trusted. */
|
|
37
|
+
processIdentity?: string;
|
|
36
38
|
startedAt: string;
|
|
37
39
|
/** Refreshed every few seconds while the supervisor is alive. */
|
|
38
40
|
heartbeatAt: string;
|
|
@@ -48,7 +50,9 @@ export declare const RUNTIME_STALE_MS = 30000;
|
|
|
48
50
|
export declare function runtimeStatePath(root: string): string;
|
|
49
51
|
export declare function readRuntimeState(root: string): RuntimeState | null;
|
|
50
52
|
export declare function isPidAlive(pid: number): boolean;
|
|
51
|
-
/**
|
|
53
|
+
/** Match a recorded process generation, including when waiting for shutdown. */
|
|
54
|
+
export declare function sameRuntimeProcess(state: RuntimeState, alive?: (pid: number) => boolean, identity?: (pid: number) => string | null): boolean;
|
|
55
|
+
/** A live supervisor requires a fresh heartbeat AND the same OS process. */
|
|
52
56
|
export declare function liveRuntime(root: string, nowMs?: number, alive?: (pid: number) => boolean): RuntimeState | null;
|
|
53
57
|
/** True when a live `fortytwo start` is currently running the named service. */
|
|
54
58
|
export declare function serviceRunning(state: RuntimeState | null, name: string): boolean;
|
package/dist/runtime.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAMhD,6DAA6D;AAC7D,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,0CAA0C;IAC1C,GAAG,EAAE,MAAM,CAAC;IACZ,gEAAgE;IAChE,GAAG,EAAE,MAAM,CAAC;IACZ,kFAAkF;IAClF,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,eAAO,MAAM,QAAQ,EAAE,WAAW,EAGjC,CAAC;AAEF,MAAM,WAAW,cAAc;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE;AAChE,MAAM,WAAW,cAAc;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE;AAEhE;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,UAAU,EAAE,MAAM,CAAC,UAAU,EAC7B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,IAAI,EAAE,MAAM,GACX,MAAM,CAAC,UAAU,CAKnB;AAED,0GAA0G;AAC1G,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,CAAC,UAAU,EACtB,KAAK,GAAE,WAAW,EAAa,GAC9B;IAAE,GAAG,EAAE,cAAc,EAAE,CAAC;IAAC,OAAO,EAAE,cAAc,EAAE,CAAA;CAAE,CAsBtD;AAID,MAAM,WAAW,YAAY;IAC3B,+CAA+C;IAC/C,GAAG,EAAE,MAAM,CAAC;IACZ,8EAA8E;IAC9E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,iEAAiE;IACjE,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,KAAK,EAAE,SAAS,GAAG,QAAQ,CAAA;KAAE,EAAE,CAAC;IAC9E,OAAO,EAAE,cAAc,EAAE,CAAC;CAC3B;AAED,yFAAyF;AACzF,eAAO,MAAM,gBAAgB,QAAS,CAAC;AAEvC,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAErD;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAMlE;AAUD,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAQ/C;AAED,gFAAgF;AAChF,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,YAAY,EACnB,KAAK,GAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAoB,EAC5C,QAAQ,GAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,IAA0B,GAC7D,OAAO,CAIT;AAED,4EAA4E;AAC5E,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,KAAK,GAAE,MAAmB,EAC1B,KAAK,GAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAoB,GAC3C,YAAY,GAAG,IAAI,CAMrB;AAED,gFAAgF;AAChF,wBAAgB,cAAc,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAEhF;AAID,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,OAAO,CAAC,EAAE,cAAc,EAAE,CAAC;IAC3B,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,8EAA8E;IAC9E,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uCAAuC;IACvC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,cAAc,EAAE,EAAE,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CAyF7F"}
|
package/dist/runtime.js
CHANGED
|
@@ -11,14 +11,14 @@
|
|
|
11
11
|
//
|
|
12
12
|
// `.fortytwo/runtime.json` records the running supervisor (its pid, a heartbeat
|
|
13
13
|
// refreshed every few seconds, and its children). `status`, `stop` and `pair`
|
|
14
|
-
// read it, and it is removed on exit.
|
|
15
|
-
//
|
|
16
|
-
// has since been reused.
|
|
14
|
+
// read it, and it is removed on exit. Both a fresh heartbeat and a matching OS
|
|
15
|
+
// process-start identity are required: a live PID alone does not prove ownership.
|
|
17
16
|
import { spawn } from 'node:child_process';
|
|
18
17
|
import { createInterface } from 'node:readline';
|
|
19
18
|
import { existsSync, readFileSync, writeFileSync, renameSync, mkdirSync, rmSync } from 'node:fs';
|
|
20
19
|
import { join, resolve } from 'node:path';
|
|
21
20
|
import { findSiblingDir } from './engine.js';
|
|
21
|
+
import { readProcessIdentity } from './process-identity.js';
|
|
22
22
|
export const SERVICES = [
|
|
23
23
|
{ name: 'telegram', pkg: '@justfortytwo/telegram', bin: 'fortytwo-telegram-bridge', requiredEnv: ['TELEGRAM_BOT_TOKEN'] },
|
|
24
24
|
{ name: 'scheduler', pkg: '@justfortytwo/scheduler', bin: 'fortytwo-scheduler', requiredEnv: [] },
|
|
@@ -89,6 +89,8 @@ function writeRuntimeState(root, state) {
|
|
|
89
89
|
renameSync(tmp, path);
|
|
90
90
|
}
|
|
91
91
|
export function isPidAlive(pid) {
|
|
92
|
+
if (!Number.isSafeInteger(pid) || pid <= 0)
|
|
93
|
+
return false;
|
|
92
94
|
try {
|
|
93
95
|
process.kill(pid, 0);
|
|
94
96
|
return true;
|
|
@@ -97,7 +99,13 @@ export function isPidAlive(pid) {
|
|
|
97
99
|
return err.code === 'EPERM'; // exists, owned by someone else
|
|
98
100
|
}
|
|
99
101
|
}
|
|
100
|
-
/**
|
|
102
|
+
/** Match a recorded process generation, including when waiting for shutdown. */
|
|
103
|
+
export function sameRuntimeProcess(state, alive = isPidAlive, identity = readProcessIdentity) {
|
|
104
|
+
return Number.isSafeInteger(state.pid) && state.pid > 0
|
|
105
|
+
&& typeof state.processIdentity === 'string' && state.processIdentity.length > 0
|
|
106
|
+
&& alive(state.pid) && identity(state.pid) === state.processIdentity;
|
|
107
|
+
}
|
|
108
|
+
/** A live supervisor requires a fresh heartbeat AND the same OS process. */
|
|
101
109
|
export function liveRuntime(root, nowMs = Date.now(), alive = isPidAlive) {
|
|
102
110
|
const s = readRuntimeState(root);
|
|
103
111
|
if (!s || typeof s.pid !== 'number')
|
|
@@ -105,7 +113,7 @@ export function liveRuntime(root, nowMs = Date.now(), alive = isPidAlive) {
|
|
|
105
113
|
const beat = new Date(s.heartbeatAt).getTime();
|
|
106
114
|
if (!Number.isFinite(beat) || nowMs - beat > RUNTIME_STALE_MS)
|
|
107
115
|
return null;
|
|
108
|
-
return
|
|
116
|
+
return sameRuntimeProcess(s, alive) ? s : null;
|
|
109
117
|
}
|
|
110
118
|
/** True when a live `fortytwo start` is currently running the named service. */
|
|
111
119
|
export function serviceRunning(state, name) {
|
|
@@ -123,6 +131,9 @@ export function supervise(services, opts) {
|
|
|
123
131
|
const signals = opts.signals ?? process;
|
|
124
132
|
const graceMs = opts.graceMs ?? 10_000;
|
|
125
133
|
const startedAt = new Date().toISOString();
|
|
134
|
+
const processIdentity = readProcessIdentity(process.pid);
|
|
135
|
+
if (!processIdentity)
|
|
136
|
+
throw new Error('Cannot establish supervisor process identity; refusing to start services.');
|
|
126
137
|
return new Promise((resolveExit) => {
|
|
127
138
|
const children = new Map();
|
|
128
139
|
const exited = new Set();
|
|
@@ -131,6 +142,7 @@ export function supervise(services, opts) {
|
|
|
131
142
|
let killTimer;
|
|
132
143
|
const state = () => ({
|
|
133
144
|
pid: process.pid,
|
|
145
|
+
processIdentity,
|
|
134
146
|
startedAt,
|
|
135
147
|
heartbeatAt: new Date().toISOString(),
|
|
136
148
|
services: services.map((s) => ({
|
package/dist/runtime.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,EAAE;AACF,kFAAkF;AAClF,+EAA+E;AAC/E,qEAAqE;AACrE,gFAAgF;AAChF,gFAAgF;AAChF,oEAAoE;AACpE,iFAAiF;AACjF,iEAAiE;AACjE,EAAE;AACF,gFAAgF;AAChF,8EAA8E;AAC9E
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@justfortytwo/installer",
|
|
3
|
-
"version": "1.0.0-
|
|
4
|
-
"description": "All-in-one installer and lifecycle CLI for fortytwo
|
|
3
|
+
"version": "1.0.0-11",
|
|
4
|
+
"description": "All-in-one installer and lifecycle CLI for fortytwo — scaffolds the persona surface and provisions the npm engine (memory MCP, safety gate, channel adapters, embedder).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Enrico Deleo",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"vitest": "^2.1.0"
|
|
46
46
|
},
|
|
47
47
|
"fortytwo": {
|
|
48
|
-
"comment": "Compatibility contract this CLI version was authored against
|
|
48
|
+
"comment": "Compatibility contract this CLI version was authored against — the SINGLE source of truth for engine sibling versions (deliberately not peerDependencies: npm would hard-fail installer upgrades with ERESOLVE whenever an installed sibling sits outside the new range). init installs these ranges, doctor cross-checks the *installed* siblings against them, update resolves latest-in-range and records the set into .fortytwo/state.json for rollback.",
|
|
49
49
|
"compat": {
|
|
50
50
|
"@justfortytwo/memory": "1.0.0-2",
|
|
51
51
|
"@justfortytwo/gate": "^0.1.0",
|