@felan-ai/daemon 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/NOTICE +69 -0
- package/README.md +61 -2
- package/dist/client.d.ts +5 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +4 -0
- package/dist/client.js.map +1 -0
- package/dist/daemon/admission.d.ts +39 -0
- package/dist/daemon/admission.d.ts.map +1 -0
- package/dist/daemon/admission.js +175 -0
- package/dist/daemon/admission.js.map +1 -0
- package/dist/daemon/agent-logs.d.ts +11 -0
- package/dist/daemon/agent-logs.d.ts.map +1 -0
- package/dist/daemon/agent-logs.js +31 -0
- package/dist/daemon/agent-logs.js.map +1 -0
- package/dist/daemon/bootstrap.d.ts +7 -0
- package/dist/daemon/bootstrap.d.ts.map +1 -0
- package/dist/daemon/bootstrap.js +4 -0
- package/dist/daemon/bootstrap.js.map +1 -0
- package/dist/daemon/broker.d.ts +94 -0
- package/dist/daemon/broker.d.ts.map +1 -0
- package/dist/daemon/broker.js +374 -0
- package/dist/daemon/broker.js.map +1 -0
- package/dist/daemon/commands.d.ts +47 -0
- package/dist/daemon/commands.d.ts.map +1 -0
- package/dist/daemon/commands.js +639 -0
- package/dist/daemon/commands.js.map +1 -0
- package/dist/daemon/control-recovery.d.ts +9 -0
- package/dist/daemon/control-recovery.d.ts.map +1 -0
- package/dist/daemon/control-recovery.js +68 -0
- package/dist/daemon/control-recovery.js.map +1 -0
- package/dist/daemon/control-state.d.ts +1915 -0
- package/dist/daemon/control-state.d.ts.map +1 -0
- package/dist/daemon/control-state.js +154 -0
- package/dist/daemon/control-state.js.map +1 -0
- package/dist/daemon/control-store.d.ts +113 -0
- package/dist/daemon/control-store.d.ts.map +1 -0
- package/dist/daemon/control-store.js +901 -0
- package/dist/daemon/control-store.js.map +1 -0
- package/dist/daemon/execution-policy.d.ts +15 -0
- package/dist/daemon/execution-policy.d.ts.map +1 -0
- package/dist/daemon/execution-policy.js +42 -0
- package/dist/daemon/execution-policy.js.map +1 -0
- package/dist/daemon/execution-services.d.ts +5 -0
- package/dist/daemon/execution-services.d.ts.map +1 -0
- package/dist/daemon/execution-services.js +73 -0
- package/dist/daemon/execution-services.js.map +1 -0
- package/dist/daemon/executions.d.ts +134 -0
- package/dist/daemon/executions.d.ts.map +1 -0
- package/dist/daemon/executions.js +486 -0
- package/dist/daemon/executions.js.map +1 -0
- package/dist/daemon/extension-ui.d.ts +24 -0
- package/dist/daemon/extension-ui.d.ts.map +1 -0
- package/dist/daemon/extension-ui.js +161 -0
- package/dist/daemon/extension-ui.js.map +1 -0
- package/dist/daemon/fanout.d.ts +40 -0
- package/dist/daemon/fanout.d.ts.map +1 -0
- package/dist/daemon/fanout.js +304 -0
- package/dist/daemon/fanout.js.map +1 -0
- package/dist/daemon/headless-json.d.ts +3 -0
- package/dist/daemon/headless-json.d.ts.map +1 -0
- package/dist/daemon/headless-json.js +20 -0
- package/dist/daemon/headless-json.js.map +1 -0
- package/dist/daemon/host-config.d.ts +61 -0
- package/dist/daemon/host-config.d.ts.map +1 -0
- package/dist/daemon/host-config.js +167 -0
- package/dist/daemon/host-config.js.map +1 -0
- package/dist/daemon/host-services.d.ts +61 -0
- package/dist/daemon/host-services.d.ts.map +1 -0
- package/dist/daemon/host-services.js +2 -0
- package/dist/daemon/host-services.js.map +1 -0
- package/dist/daemon/ipc.d.ts +14 -0
- package/dist/daemon/ipc.d.ts.map +1 -0
- package/dist/daemon/ipc.js +233 -0
- package/dist/daemon/ipc.js.map +1 -0
- package/dist/daemon/legacy-sessions.d.ts +48 -0
- package/dist/daemon/legacy-sessions.d.ts.map +1 -0
- package/dist/daemon/legacy-sessions.js +328 -0
- package/dist/daemon/legacy-sessions.js.map +1 -0
- package/dist/daemon/lifecycle.d.ts +44 -0
- package/dist/daemon/lifecycle.d.ts.map +1 -0
- package/dist/daemon/lifecycle.js +164 -0
- package/dist/daemon/lifecycle.js.map +1 -0
- package/dist/daemon/main.d.ts +3 -0
- package/dist/daemon/main.d.ts.map +1 -0
- package/dist/daemon/main.js +83 -0
- package/dist/daemon/main.js.map +1 -0
- package/dist/daemon/message-display.d.ts +4 -0
- package/dist/daemon/message-display.d.ts.map +1 -0
- package/dist/daemon/message-display.js +20 -0
- package/dist/daemon/message-display.js.map +1 -0
- package/dist/daemon/native-ownership.d.ts +13 -0
- package/dist/daemon/native-ownership.d.ts.map +1 -0
- package/dist/daemon/native-ownership.js +173 -0
- package/dist/daemon/native-ownership.js.map +1 -0
- package/dist/daemon/operational-log.d.ts +23 -0
- package/dist/daemon/operational-log.d.ts.map +1 -0
- package/dist/daemon/operational-log.js +79 -0
- package/dist/daemon/operational-log.js.map +1 -0
- package/dist/daemon/ownership.d.ts +35 -0
- package/dist/daemon/ownership.d.ts.map +1 -0
- package/dist/daemon/ownership.js +395 -0
- package/dist/daemon/ownership.js.map +1 -0
- package/dist/daemon/persistence.d.ts +110 -0
- package/dist/daemon/persistence.d.ts.map +1 -0
- package/dist/daemon/persistence.js +540 -0
- package/dist/daemon/persistence.js.map +1 -0
- package/dist/daemon/process-adapter.d.ts +23 -0
- package/dist/daemon/process-adapter.d.ts.map +1 -0
- package/dist/daemon/process-adapter.js +2 -0
- package/dist/daemon/process-adapter.js.map +1 -0
- package/dist/daemon/processes.d.ts +102 -0
- package/dist/daemon/processes.d.ts.map +1 -0
- package/dist/daemon/processes.js +691 -0
- package/dist/daemon/processes.js.map +1 -0
- package/dist/daemon/profile-storage.d.ts +16 -0
- package/dist/daemon/profile-storage.d.ts.map +1 -0
- package/dist/daemon/profile-storage.js +148 -0
- package/dist/daemon/profile-storage.js.map +1 -0
- package/dist/daemon/projection.d.ts +110 -0
- package/dist/daemon/projection.d.ts.map +1 -0
- package/dist/daemon/projection.js +661 -0
- package/dist/daemon/projection.js.map +1 -0
- package/dist/daemon/provider-loader.d.ts +28 -0
- package/dist/daemon/provider-loader.d.ts.map +1 -0
- package/dist/daemon/provider-loader.js +376 -0
- package/dist/daemon/provider-loader.js.map +1 -0
- package/dist/daemon/provider.d.ts +92 -0
- package/dist/daemon/provider.d.ts.map +1 -0
- package/dist/daemon/provider.js +31 -0
- package/dist/daemon/provider.js.map +1 -0
- package/dist/daemon/registry.d.ts +209 -0
- package/dist/daemon/registry.d.ts.map +1 -0
- package/dist/daemon/registry.js +1591 -0
- package/dist/daemon/registry.js.map +1 -0
- package/dist/daemon/runtime-dependencies.d.ts +5 -0
- package/dist/daemon/runtime-dependencies.d.ts.map +1 -0
- package/dist/daemon/runtime-dependencies.js +31 -0
- package/dist/daemon/runtime-dependencies.js.map +1 -0
- package/dist/daemon/server.d.ts +110 -0
- package/dist/daemon/server.d.ts.map +1 -0
- package/dist/daemon/server.js +556 -0
- package/dist/daemon/server.js.map +1 -0
- package/dist/daemon/service.d.ts +38 -0
- package/dist/daemon/service.d.ts.map +1 -0
- package/dist/daemon/service.js +275 -0
- package/dist/daemon/service.js.map +1 -0
- package/dist/daemon/session-cursor.d.ts +3 -0
- package/dist/daemon/session-cursor.d.ts.map +1 -0
- package/dist/daemon/session-cursor.js +4 -0
- package/dist/daemon/session-cursor.js.map +1 -0
- package/dist/daemon/session-execution.d.ts +88 -0
- package/dist/daemon/session-execution.d.ts.map +1 -0
- package/dist/daemon/session-execution.js +2 -0
- package/dist/daemon/session-execution.js.map +1 -0
- package/dist/daemon/session-executions.d.ts +5 -0
- package/dist/daemon/session-executions.d.ts.map +1 -0
- package/dist/daemon/session-executions.js +146 -0
- package/dist/daemon/session-executions.js.map +1 -0
- package/dist/daemon/session-files.d.ts +28 -0
- package/dist/daemon/session-files.d.ts.map +1 -0
- package/dist/daemon/session-files.js +189 -0
- package/dist/daemon/session-files.js.map +1 -0
- package/dist/daemon/session-lifecycle-contracts.d.ts +104 -0
- package/dist/daemon/session-lifecycle-contracts.d.ts.map +1 -0
- package/dist/daemon/session-lifecycle-contracts.js +2 -0
- package/dist/daemon/session-lifecycle-contracts.js.map +1 -0
- package/dist/daemon/session-lifecycle.d.ts +26 -0
- package/dist/daemon/session-lifecycle.d.ts.map +1 -0
- package/dist/daemon/session-lifecycle.js +246 -0
- package/dist/daemon/session-lifecycle.js.map +1 -0
- package/dist/daemon/session-runtime.d.ts +64 -0
- package/dist/daemon/session-runtime.d.ts.map +1 -0
- package/dist/daemon/session-runtime.js +3 -0
- package/dist/daemon/session-runtime.js.map +1 -0
- package/dist/daemon/session-services.d.ts +6 -0
- package/dist/daemon/session-services.d.ts.map +1 -0
- package/dist/daemon/session-services.js +144 -0
- package/dist/daemon/session-services.js.map +1 -0
- package/dist/daemon/shutdown-error.d.ts +12 -0
- package/dist/daemon/shutdown-error.d.ts.map +1 -0
- package/dist/daemon/shutdown-error.js +51 -0
- package/dist/daemon/shutdown-error.js.map +1 -0
- package/dist/daemon/supervisor.d.ts +28 -0
- package/dist/daemon/supervisor.d.ts.map +1 -0
- package/dist/daemon/supervisor.js +159 -0
- package/dist/daemon/supervisor.js.map +1 -0
- package/dist/daemon/target.d.ts +55 -0
- package/dist/daemon/target.d.ts.map +1 -0
- package/dist/daemon/target.js +191 -0
- package/dist/daemon/target.js.map +1 -0
- package/dist/daemon/tree.d.ts +7 -0
- package/dist/daemon/tree.d.ts.map +1 -0
- package/dist/daemon/tree.js +126 -0
- package/dist/daemon/tree.js.map +1 -0
- package/dist/daemon/ui-vocabulary.d.ts +29 -0
- package/dist/daemon/ui-vocabulary.d.ts.map +1 -0
- package/dist/daemon/ui-vocabulary.js +323 -0
- package/dist/daemon/ui-vocabulary.js.map +1 -0
- package/dist/daemon/worker.d.ts +5 -0
- package/dist/daemon/worker.d.ts.map +1 -0
- package/dist/daemon/worker.js +49 -0
- package/dist/daemon/worker.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/lock.d.ts +27 -0
- package/dist/lock.d.ts.map +1 -0
- package/dist/lock.js +432 -0
- package/dist/lock.js.map +1 -0
- package/dist/logger.d.ts +9 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +56 -0
- package/dist/logger.js.map +1 -0
- package/dist/remote/backoff.d.ts +17 -0
- package/dist/remote/backoff.d.ts.map +1 -0
- package/dist/remote/backoff.js +18 -0
- package/dist/remote/backoff.js.map +1 -0
- package/dist/remote/batch.d.ts +3 -0
- package/dist/remote/batch.d.ts.map +1 -0
- package/dist/remote/batch.js +27 -0
- package/dist/remote/batch.js.map +1 -0
- package/dist/remote/command-journal.d.ts +30 -0
- package/dist/remote/command-journal.d.ts.map +1 -0
- package/dist/remote/command-journal.js +72 -0
- package/dist/remote/command-journal.js.map +1 -0
- package/dist/remote/commands.d.ts +48 -0
- package/dist/remote/commands.d.ts.map +1 -0
- package/dist/remote/commands.js +145 -0
- package/dist/remote/commands.js.map +1 -0
- package/dist/remote/connector.d.ts +135 -0
- package/dist/remote/connector.d.ts.map +1 -0
- package/dist/remote/connector.js +1069 -0
- package/dist/remote/connector.js.map +1 -0
- package/dist/remote/content.d.ts +17 -0
- package/dist/remote/content.d.ts.map +1 -0
- package/dist/remote/content.js +116 -0
- package/dist/remote/content.js.map +1 -0
- package/dist/remote/outbox.d.ts +52 -0
- package/dist/remote/outbox.d.ts.map +1 -0
- package/dist/remote/outbox.js +321 -0
- package/dist/remote/outbox.js.map +1 -0
- package/dist/remote/platform.d.ts +53 -0
- package/dist/remote/platform.d.ts.map +1 -0
- package/dist/remote/platform.js +231 -0
- package/dist/remote/platform.js.map +1 -0
- package/dist/remote/realtime.d.ts +45 -0
- package/dist/remote/realtime.d.ts.map +1 -0
- package/dist/remote/realtime.js +265 -0
- package/dist/remote/realtime.js.map +1 -0
- package/dist/remote/sharing.d.ts +16 -0
- package/dist/remote/sharing.d.ts.map +1 -0
- package/dist/remote/sharing.js +24 -0
- package/dist/remote/sharing.js.map +1 -0
- package/dist/remote/state.d.ts +52 -0
- package/dist/remote/state.d.ts.map +1 -0
- package/dist/remote/state.js +156 -0
- package/dist/remote/state.js.map +1 -0
- package/dist/remote/text.d.ts +11 -0
- package/dist/remote/text.d.ts.map +1 -0
- package/dist/remote/text.js +188 -0
- package/dist/remote/text.js.map +1 -0
- package/dist/remote/token.d.ts +39 -0
- package/dist/remote/token.d.ts.map +1 -0
- package/dist/remote/token.js +238 -0
- package/dist/remote/token.js.map +1 -0
- package/dist/runtime-factory.d.ts +12 -0
- package/dist/runtime-factory.d.ts.map +1 -0
- package/dist/runtime-factory.js +12 -0
- package/dist/runtime-factory.js.map +1 -0
- package/dist/session-history.d.ts +29 -0
- package/dist/session-history.d.ts.map +1 -0
- package/dist/session-history.js +374 -0
- package/dist/session-history.js.map +1 -0
- package/dist/setup/dependencies.d.ts +15 -0
- package/dist/setup/dependencies.d.ts.map +1 -0
- package/dist/setup/dependencies.js +2 -0
- package/dist/setup/dependencies.js.map +1 -0
- package/dist/setup/open.d.ts +8 -0
- package/dist/setup/open.d.ts.map +1 -0
- package/dist/setup/open.js +16 -0
- package/dist/setup/open.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +4 -0
- package/dist/version.js.map +1 -0
- package/package.json +65 -3
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type DaemonIdentity } from '@felan-ai/session-protocol';
|
|
2
|
+
import { type DaemonTarget } from './target.js';
|
|
3
|
+
import type { DaemonOwnership } from './ownership.js';
|
|
4
|
+
export interface DaemonLaunchReceipt {
|
|
5
|
+
readonly target: DaemonTarget;
|
|
6
|
+
readonly identity: DaemonIdentity;
|
|
7
|
+
readonly daemonVersion: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function spawnDetachedDaemon(options: {
|
|
10
|
+
target: DaemonTarget;
|
|
11
|
+
entrypoint: string;
|
|
12
|
+
hostConfigPath?: string;
|
|
13
|
+
timeoutMs?: number;
|
|
14
|
+
replacing?: DaemonIdentity;
|
|
15
|
+
}): Promise<DaemonLaunchReceipt>;
|
|
16
|
+
export declare function publishDaemonReadiness(owner: DaemonOwnership, version: string, timeoutMs?: number): Promise<void>;
|
|
17
|
+
export declare class BoundedDaemonLogs {
|
|
18
|
+
private readonly owner;
|
|
19
|
+
private readonly limitBytes;
|
|
20
|
+
private readonly files;
|
|
21
|
+
private readonly buffers;
|
|
22
|
+
private closed;
|
|
23
|
+
constructor(owner: DaemonOwnership, limitBytes?: number);
|
|
24
|
+
read(stream: 'stdout' | 'stderr'): string;
|
|
25
|
+
write(stream: 'stdout' | 'stderr', diagnostic: string): void;
|
|
26
|
+
close(): void;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=supervisor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"supervisor.d.ts","sourceRoot":"","sources":["../../src/daemon/supervisor.ts"],"names":[],"mappings":"AAIA,OAAO,EAAe,KAAK,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAG9E,OAAO,EAA8D,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAC5G,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEtD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAChC;AAED,wBAAsB,mBAAmB,CAAC,OAAO,EAAE;IACjD,MAAM,EAAE,YAAY,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,cAAc,CAAC;CAC5B,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAgD/B;AAED,wBAAsB,sBAAsB,CAAC,KAAK,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBvH;AAED,qBAAa,iBAAiB;IAIhB,OAAO,CAAC,QAAQ,CAAC,KAAK;IAAmB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAHhF,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAsC;IAC5D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAwD;IAChF,OAAO,CAAC,MAAM,CAAS;gBACM,KAAK,EAAE,eAAe,EAAmB,UAAU,SAAS;IAmBzF,IAAI,CAAC,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM;IAIzC,KAAK,CAAC,MAAM,EAAE,QAAQ,GAAG,QAAQ,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IAO5D,KAAK,IAAI,IAAI;CAId"}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { closeSync, fstatSync, ftruncateSync, readSync, realpathSync, writeSync } from 'node:fs';
|
|
3
|
+
import { Socket } from 'node:net';
|
|
4
|
+
import { isAbsolute, join } from 'node:path';
|
|
5
|
+
import { encodeFrame } from '@felan-ai/session-protocol';
|
|
6
|
+
import { DaemonSecurityError } from './native-ownership.js';
|
|
7
|
+
import { probeDaemon, readControlFrame, readinessResponse } from './ipc.js';
|
|
8
|
+
import { assertTargetIdentity, openPrivateFile, resolveDaemonTarget } from './target.js';
|
|
9
|
+
export async function spawnDetachedDaemon(options) {
|
|
10
|
+
const target = resolveDaemonTarget(options.target);
|
|
11
|
+
const executable = realpathSync(process.execPath);
|
|
12
|
+
const entrypoint = realpathSync(options.entrypoint);
|
|
13
|
+
const timeoutMs = options.timeoutMs ?? 10_000;
|
|
14
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs < 100 || timeoutMs > 60_000)
|
|
15
|
+
throw new DaemonSecurityError('invalid_launch', 'Readiness deadline must be between 100 and 60000 milliseconds.');
|
|
16
|
+
if (options.hostConfigPath !== undefined && (!isAbsolute(options.hostConfigPath) || Buffer.byteLength(options.hostConfigPath) > 4096 || options.hostConfigPath.includes('\0')))
|
|
17
|
+
throw new DaemonSecurityError('invalid_launch', 'Explicit host configuration must be a bounded absolute path.');
|
|
18
|
+
if (options.replacing)
|
|
19
|
+
assertTargetIdentity(target, options.replacing, options.replacing);
|
|
20
|
+
const child = spawn(executable, [entrypoint, JSON.stringify(options.target), ...(options.hostConfigPath ? ['--host-config', options.hostConfigPath] : []),
|
|
21
|
+
...(options.replacing ? ['--replace', JSON.stringify(options.replacing)] : [])], {
|
|
22
|
+
cwd: process.cwd(),
|
|
23
|
+
env: process.env,
|
|
24
|
+
detached: true,
|
|
25
|
+
windowsHide: true,
|
|
26
|
+
stdio: ['ignore', 'ignore', 'ignore', 'pipe'],
|
|
27
|
+
});
|
|
28
|
+
const deadline = performance.now() + timeoutMs;
|
|
29
|
+
const channel = child.stdio[3];
|
|
30
|
+
let exitError;
|
|
31
|
+
const exited = new Promise((_resolve, reject) => { exitError = reject; });
|
|
32
|
+
const onError = () => exitError?.(new DaemonSecurityError('launch_failed', 'Could not spawn the resolved Node executable.'));
|
|
33
|
+
const onExit = (code) => exitError?.(new DaemonSecurityError('launch_failed', `Daemon child exited before authenticated readiness (exit ${code ?? 'signal'}). Inspect its bounded runtime diagnostics.`));
|
|
34
|
+
child.once('error', onError);
|
|
35
|
+
child.once('exit', onExit);
|
|
36
|
+
channel.on('error', () => { });
|
|
37
|
+
try {
|
|
38
|
+
const ready = await Promise.race([readControlFrame(channel, timeoutMs), exited]);
|
|
39
|
+
assertTargetIdentity(target, ready.identity, ready.identity);
|
|
40
|
+
if (ready.re !== 'launch' || ready.state !== 'ready' || ready.outcome !== 'accepted')
|
|
41
|
+
throw new DaemonSecurityError('invalid_readiness', 'Child did not report an available daemon.');
|
|
42
|
+
const remaining = deadline - performance.now();
|
|
43
|
+
if (remaining <= 0)
|
|
44
|
+
throw new DaemonSecurityError('readiness_timeout', 'Daemon did not become ready before the deadline.');
|
|
45
|
+
await probeDaemon(target, ready.identity, Math.min(remaining, 2_000));
|
|
46
|
+
await new Promise((resolve, reject) => channel.write(Buffer.from([1]), error => error ? reject(error) : resolve()));
|
|
47
|
+
channel.end();
|
|
48
|
+
channel.unref();
|
|
49
|
+
child.unref();
|
|
50
|
+
return Object.freeze({ target: options.target, identity: ready.identity, daemonVersion: ready.daemonVersion });
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
if (error instanceof DaemonSecurityError && error.code === 'unavailable' && channel.readableEnded) {
|
|
54
|
+
let timer;
|
|
55
|
+
try {
|
|
56
|
+
await Promise.race([exited, new Promise(resolve => { timer = setTimeout(resolve, Math.max(0, Math.min(100, deadline - performance.now()))); })]);
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
clearTimeout(timer);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
throw error;
|
|
63
|
+
}
|
|
64
|
+
finally {
|
|
65
|
+
child.off('error', onError);
|
|
66
|
+
child.off('exit', onExit);
|
|
67
|
+
// Closing the launch channel aborts an unacknowledged cooperative child. Never signal a PID from a receipt.
|
|
68
|
+
if (!channel.writableEnded)
|
|
69
|
+
channel.destroy();
|
|
70
|
+
child.unref();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
export async function publishDaemonReadiness(owner, version, timeoutMs = 10_000) {
|
|
74
|
+
owner.assertCurrent();
|
|
75
|
+
const channel = new Socket({ fd: 3, readable: true, writable: true });
|
|
76
|
+
try {
|
|
77
|
+
await new Promise((resolve, reject) => {
|
|
78
|
+
const timeout = setTimeout(() => reject(new DaemonSecurityError('launch_aborted', 'Launcher did not acknowledge readiness.')), timeoutMs);
|
|
79
|
+
const settle = (error) => {
|
|
80
|
+
clearTimeout(timeout);
|
|
81
|
+
channel.removeAllListeners('data');
|
|
82
|
+
channel.removeAllListeners('end');
|
|
83
|
+
channel.removeAllListeners('error');
|
|
84
|
+
if (error)
|
|
85
|
+
reject(error);
|
|
86
|
+
else
|
|
87
|
+
resolve();
|
|
88
|
+
};
|
|
89
|
+
channel.once('data', (bytes) => settle(bytes.length === 1 && bytes[0] === 1 ? undefined : new DaemonSecurityError('launch_aborted', 'Invalid readiness acknowledgement.')));
|
|
90
|
+
channel.once('end', () => settle(new DaemonSecurityError('launch_aborted', 'Launcher left before readiness.')));
|
|
91
|
+
channel.once('error', () => settle(new DaemonSecurityError('launch_aborted', 'Launch channel failed.')));
|
|
92
|
+
channel.write(encodeFrame(readinessResponse(owner, version, 'launch')));
|
|
93
|
+
});
|
|
94
|
+
owner.assertCurrent();
|
|
95
|
+
}
|
|
96
|
+
finally {
|
|
97
|
+
channel.destroy();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
export class BoundedDaemonLogs {
|
|
101
|
+
owner;
|
|
102
|
+
limitBytes;
|
|
103
|
+
files;
|
|
104
|
+
buffers = { stdout: Buffer.alloc(0), stderr: Buffer.alloc(0) };
|
|
105
|
+
closed = false;
|
|
106
|
+
constructor(owner, limitBytes = 32_768) {
|
|
107
|
+
this.owner = owner;
|
|
108
|
+
this.limitBytes = limitBytes;
|
|
109
|
+
owner.assertCurrent();
|
|
110
|
+
if (!Number.isInteger(limitBytes) || limitBytes < 128 || limitBytes > 1_048_576)
|
|
111
|
+
throw new DaemonSecurityError('invalid_logs', 'Diagnostic capacity must be between 128 and 1048576 bytes.');
|
|
112
|
+
const stdout = openPrivateFile(join(owner.target.runtimeDirectory, 'stdout.log'), owner.target.uid);
|
|
113
|
+
let stderr;
|
|
114
|
+
try {
|
|
115
|
+
stderr = openPrivateFile(join(owner.target.runtimeDirectory, 'stderr.log'), owner.target.uid);
|
|
116
|
+
this.files = { stdout, stderr };
|
|
117
|
+
for (const stream of ['stdout', 'stderr']) {
|
|
118
|
+
const size = fstatSync(this.files[stream]).size;
|
|
119
|
+
if (!Number.isSafeInteger(size))
|
|
120
|
+
throw new DaemonSecurityError('invalid_logs', 'Diagnostic size is unsafe.');
|
|
121
|
+
const tail = Buffer.alloc(Math.min(size, limitBytes));
|
|
122
|
+
const bytes = readSync(this.files[stream], tail, 0, tail.length, size - tail.length);
|
|
123
|
+
this.buffers[stream] = tail.subarray(0, bytes);
|
|
124
|
+
ftruncateSync(this.files[stream], bytes);
|
|
125
|
+
if (bytes)
|
|
126
|
+
writeSync(this.files[stream], this.buffers[stream], 0, bytes, 0);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
closeSync(stdout);
|
|
131
|
+
if (stderr !== undefined)
|
|
132
|
+
closeSync(stderr);
|
|
133
|
+
throw error;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
read(stream) {
|
|
137
|
+
if (this.closed)
|
|
138
|
+
throw new DaemonSecurityError('logs_closed', 'Daemon diagnostic sink is closed.');
|
|
139
|
+
this.owner.assertCurrent();
|
|
140
|
+
return this.buffers[stream].toString('utf8');
|
|
141
|
+
}
|
|
142
|
+
write(stream, diagnostic) {
|
|
143
|
+
if (this.closed)
|
|
144
|
+
throw new DaemonSecurityError('logs_closed', 'Daemon diagnostic sink is closed.');
|
|
145
|
+
this.owner.assertCurrent();
|
|
146
|
+
const bytes = Buffer.from(`${diagnostic.slice(-this.limitBytes).replace(/[\u0000-\u0008\u000b-\u001f\u007f]/g, '?')}\n`);
|
|
147
|
+
this.buffers[stream] = Buffer.concat([this.buffers[stream], bytes.subarray(-this.limitBytes)]).subarray(-this.limitBytes);
|
|
148
|
+
ftruncateSync(this.files[stream], 0);
|
|
149
|
+
writeSync(this.files[stream], this.buffers[stream], 0, this.buffers[stream].length, 0);
|
|
150
|
+
}
|
|
151
|
+
close() {
|
|
152
|
+
if (this.closed)
|
|
153
|
+
return;
|
|
154
|
+
this.closed = true;
|
|
155
|
+
closeSync(this.files.stdout);
|
|
156
|
+
closeSync(this.files.stderr);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=supervisor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"supervisor.js","sourceRoot":"","sources":["../../src/daemon/supervisor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { type BigIntStats } from 'node:fs';
|
|
2
|
+
import type { DaemonIdentity, DaemonTarget as ProtocolDaemonTarget } from '@felan-ai/session-protocol';
|
|
3
|
+
export type DaemonTarget = {
|
|
4
|
+
readonly kind: 'production';
|
|
5
|
+
readonly agentDir: string;
|
|
6
|
+
readonly storeRoots: readonly string[];
|
|
7
|
+
} | {
|
|
8
|
+
readonly kind: 'isolated';
|
|
9
|
+
readonly directory: string;
|
|
10
|
+
readonly namespaceId: string;
|
|
11
|
+
readonly storeRoots?: readonly string[];
|
|
12
|
+
};
|
|
13
|
+
export interface PathIdentity {
|
|
14
|
+
readonly path: string;
|
|
15
|
+
readonly dev: bigint;
|
|
16
|
+
readonly ino: bigint;
|
|
17
|
+
readonly mode: bigint;
|
|
18
|
+
readonly uid: bigint;
|
|
19
|
+
readonly links: bigint;
|
|
20
|
+
}
|
|
21
|
+
export interface ResolvedDaemonTarget {
|
|
22
|
+
readonly kind: DaemonTarget['kind'];
|
|
23
|
+
readonly namespaceId: string;
|
|
24
|
+
readonly uid: number;
|
|
25
|
+
readonly accountDirectory: string;
|
|
26
|
+
readonly runtimeDirectory: string;
|
|
27
|
+
readonly endpoint: string;
|
|
28
|
+
readonly agentDir: string;
|
|
29
|
+
readonly rootSet: readonly string[];
|
|
30
|
+
readonly pins: readonly PathIdentity[];
|
|
31
|
+
}
|
|
32
|
+
export declare function pathInside(parent: string, child: string): boolean;
|
|
33
|
+
export declare function pathsOverlap(a: string, b: string): boolean;
|
|
34
|
+
export declare function pathIdentity(path: string): PathIdentity;
|
|
35
|
+
export declare function assertPathIdentity(pin: PathIdentity): void;
|
|
36
|
+
export declare function assertPrivateStat(stat: BigIntStats, uid: number, directory: boolean): void;
|
|
37
|
+
export declare function privateDirectory(path: string, uid: number): string;
|
|
38
|
+
/** Creates a store directory without imposing permissions on an existing user directory. */
|
|
39
|
+
export declare function storeDirectory(path: string): string;
|
|
40
|
+
export declare function pinPathChain(path: string, uid: number): PathIdentity[];
|
|
41
|
+
export declare function pinPathAncestry(path: string): PathIdentity[];
|
|
42
|
+
export declare function openPrivateFile(path: string, uid: number): number;
|
|
43
|
+
export declare function realAccountLocation(): {
|
|
44
|
+
uid: number;
|
|
45
|
+
home: string;
|
|
46
|
+
directory: string;
|
|
47
|
+
};
|
|
48
|
+
export declare function resolveDaemonTarget(target: DaemonTarget): ResolvedDaemonTarget;
|
|
49
|
+
export declare function prepareDaemonTarget(target: ResolvedDaemonTarget): ResolvedDaemonTarget;
|
|
50
|
+
export declare function canonicalProspectivePath(path: string): string;
|
|
51
|
+
export declare function identityFor(target: ResolvedDaemonTarget, instanceId: string): DaemonIdentity;
|
|
52
|
+
export declare function protocolTarget(target: ResolvedDaemonTarget): ProtocolDaemonTarget;
|
|
53
|
+
/** Store roots are excluded: a daemon may own more roots than a client declared. */
|
|
54
|
+
export declare function assertTargetIdentity(target: ResolvedDaemonTarget, expected: DaemonIdentity, actual: DaemonIdentity): void;
|
|
55
|
+
//# sourceMappingURL=target.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"target.d.ts","sourceRoot":"","sources":["../../src/daemon/target.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { constants, fstatSync, lstatSync, mkdirSync, openSync, closeSync, realpathSync } from 'node:fs';
|
|
2
|
+
import { userInfo } from 'node:os';
|
|
3
|
+
import { dirname, isAbsolute, join, parse, relative, resolve, sep } from 'node:path';
|
|
4
|
+
import { DaemonSecurityError, requireOwnershipPlatform, socketPathLimit } from './native-ownership.js';
|
|
5
|
+
export function pathInside(parent, child) {
|
|
6
|
+
const rel = relative(parent, child);
|
|
7
|
+
return rel === '' || (!rel.startsWith(`..${sep}`) && rel !== '..' && !isAbsolute(rel));
|
|
8
|
+
}
|
|
9
|
+
export function pathsOverlap(a, b) { return pathInside(a, b) || pathInside(b, a); }
|
|
10
|
+
export function pathIdentity(path) {
|
|
11
|
+
const stat = lstatSync(path, { bigint: true });
|
|
12
|
+
return { path, dev: stat.dev, ino: stat.ino, mode: stat.mode, uid: stat.uid, links: stat.isDirectory() ? 0n : stat.nlink };
|
|
13
|
+
}
|
|
14
|
+
export function assertPathIdentity(pin) {
|
|
15
|
+
try {
|
|
16
|
+
const current = pathIdentity(pin.path);
|
|
17
|
+
if (current.dev === pin.dev && current.ino === pin.ino)
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
catch { /* Missing paths are ownership loss, not permission to recreate them. */ }
|
|
21
|
+
throw new DaemonSecurityError('ownership_lost', 'A daemon-owned path was replaced or removed. Stop this instance before recovery.');
|
|
22
|
+
}
|
|
23
|
+
export function assertPrivateStat(stat, uid, directory) {
|
|
24
|
+
if ((directory ? !stat.isDirectory() : !stat.isFile()) || stat.uid !== BigInt(uid) || (stat.mode & 63n) !== 0n || (!directory && stat.nlink !== 1n)) {
|
|
25
|
+
throw new DaemonSecurityError('unsafe_path', 'Daemon path must be owner-only, non-symlink and owned by the real OS account (regular files require one link).');
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export function privateDirectory(path, uid) {
|
|
29
|
+
if (!isAbsolute(path) || path.includes('\0'))
|
|
30
|
+
throw new DaemonSecurityError('unsafe_path', 'Daemon directories must be absolute paths without NUL.');
|
|
31
|
+
const parent = dirname(path);
|
|
32
|
+
if (parent !== path && !exists(parent))
|
|
33
|
+
privateDirectory(parent, uid);
|
|
34
|
+
try {
|
|
35
|
+
mkdirSync(path, { mode: 0o700 });
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
if (error.code !== 'EEXIST')
|
|
39
|
+
throw error;
|
|
40
|
+
}
|
|
41
|
+
assertPrivateStat(lstatSync(path, { bigint: true }), uid, true);
|
|
42
|
+
return realpathSync(path);
|
|
43
|
+
}
|
|
44
|
+
/** Creates a store directory without imposing permissions on an existing user directory. */
|
|
45
|
+
export function storeDirectory(path) {
|
|
46
|
+
mkdirSync(path, { recursive: true, mode: 0o700 });
|
|
47
|
+
return realpathSync(path);
|
|
48
|
+
}
|
|
49
|
+
function exists(path) { try {
|
|
50
|
+
lstatSync(path);
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
if (error.code === 'ENOENT')
|
|
55
|
+
return false;
|
|
56
|
+
throw error;
|
|
57
|
+
} }
|
|
58
|
+
export function pinPathChain(path, uid) {
|
|
59
|
+
const pins = [];
|
|
60
|
+
for (let at = path;; at = dirname(at)) {
|
|
61
|
+
const stat = lstatSync(at, { bigint: true });
|
|
62
|
+
if (!stat.isDirectory() || (stat.uid !== 0n && stat.uid !== BigInt(uid)) || ((stat.mode & 18n) !== 0n && !(stat.uid === 0n && (stat.mode & 512n) !== 0n))) {
|
|
63
|
+
throw new DaemonSecurityError('unsafe_path', 'Daemon path has an untrusted or writable non-sticky ancestor.');
|
|
64
|
+
}
|
|
65
|
+
pins.push(pathIdentity(at));
|
|
66
|
+
if (dirname(at) === at)
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
return pins;
|
|
70
|
+
}
|
|
71
|
+
export function pinPathAncestry(path) {
|
|
72
|
+
const pins = [];
|
|
73
|
+
for (let at = path;; at = dirname(at)) {
|
|
74
|
+
pins.push(pathIdentity(at));
|
|
75
|
+
if (dirname(at) === at)
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
return pins;
|
|
79
|
+
}
|
|
80
|
+
export function openPrivateFile(path, uid) {
|
|
81
|
+
const fd = openSync(path, constants.O_RDWR | constants.O_CREAT | constants.O_NOFOLLOW, 0o600);
|
|
82
|
+
try {
|
|
83
|
+
const stat = fstatSync(fd, { bigint: true });
|
|
84
|
+
assertPrivateStat(stat, uid, false);
|
|
85
|
+
const pin = pathIdentity(path);
|
|
86
|
+
if (stat.dev !== pin.dev || stat.ino !== pin.ino)
|
|
87
|
+
throw new DaemonSecurityError('unsafe_path', 'Daemon file changed while opening.');
|
|
88
|
+
return fd;
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
closeSync(fd);
|
|
92
|
+
throw error;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
export function realAccountLocation() {
|
|
96
|
+
const platform = requireOwnershipPlatform();
|
|
97
|
+
const account = userInfo();
|
|
98
|
+
const home = realpathSync(account.homedir);
|
|
99
|
+
const temp = realpathSync(platform === 'darwin' ? '/private/tmp' : '/tmp');
|
|
100
|
+
return { uid: account.uid, home, directory: join(temp, `felan-${account.uid}-daemon-v1`) };
|
|
101
|
+
}
|
|
102
|
+
export function resolveDaemonTarget(target) {
|
|
103
|
+
if (!target || (target.kind !== 'production' && target.kind !== 'isolated'))
|
|
104
|
+
throw new DaemonSecurityError('invalid_target', 'An explicit production or isolated target is required.');
|
|
105
|
+
if (target.kind === 'production' && !Array.isArray(target.storeRoots))
|
|
106
|
+
throw new DaemonSecurityError('invalid_target', 'Production targets require an explicit store-root array.');
|
|
107
|
+
if (target.storeRoots !== undefined && (!Array.isArray(target.storeRoots) || target.storeRoots.some(root => typeof root !== 'string')))
|
|
108
|
+
throw new DaemonSecurityError('invalid_target', 'Store roots must be an array of absolute paths.');
|
|
109
|
+
const account = realAccountLocation();
|
|
110
|
+
let agentDir;
|
|
111
|
+
let runtimeDirectory;
|
|
112
|
+
let namespaceId;
|
|
113
|
+
let roots;
|
|
114
|
+
let fixtureDirectory;
|
|
115
|
+
if (target.kind === 'isolated') {
|
|
116
|
+
if (typeof target.namespaceId !== 'string' || !/^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$/.test(target.namespaceId) || target.namespaceId === 'production')
|
|
117
|
+
throw new DaemonSecurityError('invalid_target', 'An isolated target requires a non-production namespace ID.');
|
|
118
|
+
// Resolve existing ancestors before creating anything, so an alias cannot redirect a fixture into production.
|
|
119
|
+
const directory = canonicalProspectivePath(target.directory);
|
|
120
|
+
fixtureDirectory = directory;
|
|
121
|
+
if (pathsOverlap(directory, canonicalProspectivePath(join(account.home, '.felan'))) || pathsOverlap(directory, account.directory) || directory === parse(directory).root)
|
|
122
|
+
throw new DaemonSecurityError('invalid_target', 'An isolated target cannot contain or use production paths.');
|
|
123
|
+
agentDir = join(directory, 'agent');
|
|
124
|
+
runtimeDirectory = join(directory, 'runtime');
|
|
125
|
+
namespaceId = target.namespaceId;
|
|
126
|
+
roots = target.storeRoots ?? [join(agentDir, 'storage')];
|
|
127
|
+
if (roots.some(root => !pathInside(directory, canonicalProspectivePath(root))))
|
|
128
|
+
throw new DaemonSecurityError('invalid_target', 'All isolated stores must remain inside the explicit fixture directory.');
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
agentDir = target.agentDir;
|
|
132
|
+
runtimeDirectory = join(account.directory, 'production');
|
|
133
|
+
namespaceId = 'production';
|
|
134
|
+
roots = target.storeRoots;
|
|
135
|
+
}
|
|
136
|
+
agentDir = canonicalProspectivePath(agentDir);
|
|
137
|
+
const allRoots = [...new Set([agentDir, ...roots.map(canonicalProspectivePath)])].sort();
|
|
138
|
+
const rootSet = allRoots.filter((root, i) => !allRoots.some((parent, j) => j !== i && pathInside(parent, root)));
|
|
139
|
+
runtimeDirectory = canonicalProspectivePath(runtimeDirectory);
|
|
140
|
+
if (fixtureDirectory && runtimeDirectory !== join(fixtureDirectory, 'runtime'))
|
|
141
|
+
throw new DaemonSecurityError('invalid_target', 'The isolated runtime directory must not be a symlink.');
|
|
142
|
+
if (fixtureDirectory && [agentDir, runtimeDirectory, ...rootSet].some(path => !pathInside(fixtureDirectory, path)))
|
|
143
|
+
throw new DaemonSecurityError('invalid_target', 'Isolated agent, runtime and stores must remain inside the canonical fixture directory.');
|
|
144
|
+
if (!fixtureDirectory && !pathInside(account.directory, runtimeDirectory))
|
|
145
|
+
throw new DaemonSecurityError('invalid_target', 'Production runtime cannot be redirected outside the account coordinator.');
|
|
146
|
+
if (rootSet.some(root => pathsOverlap(root, account.directory)))
|
|
147
|
+
throw new DaemonSecurityError('invalid_target', 'Store roots cannot overlap the account coordinator.');
|
|
148
|
+
if (exists(runtimeDirectory))
|
|
149
|
+
assertPrivateStat(lstatSync(runtimeDirectory, { bigint: true }), account.uid, true);
|
|
150
|
+
const nearest = (path) => { while (!exists(path))
|
|
151
|
+
path = dirname(path); return path; };
|
|
152
|
+
const pins = [...pinPathChain(nearest(runtimeDirectory), account.uid), ...rootSet.flatMap(root => pinPathAncestry(nearest(root)))];
|
|
153
|
+
const endpoint = join(runtimeDirectory, 'ipc.sock');
|
|
154
|
+
if (Buffer.byteLength(endpoint) > socketPathLimit())
|
|
155
|
+
throw new DaemonSecurityError('invalid_endpoint', `Use a shorter explicit runtime directory: endpoint exceeds ${socketPathLimit()} bytes.`);
|
|
156
|
+
return Object.freeze({ kind: target.kind, uid: account.uid, namespaceId, accountDirectory: account.directory, runtimeDirectory, endpoint, agentDir, rootSet: Object.freeze(rootSet), pins: Object.freeze(pins) });
|
|
157
|
+
}
|
|
158
|
+
export function prepareDaemonTarget(target) {
|
|
159
|
+
for (const pin of target.pins)
|
|
160
|
+
assertPathIdentity(pin);
|
|
161
|
+
for (const root of [target.agentDir, ...target.rootSet])
|
|
162
|
+
storeDirectory(root);
|
|
163
|
+
privateDirectory(target.runtimeDirectory, target.uid);
|
|
164
|
+
for (const pin of target.pins)
|
|
165
|
+
assertPathIdentity(pin);
|
|
166
|
+
return Object.freeze({ ...target, pins: Object.freeze([...pinPathChain(target.runtimeDirectory, target.uid), ...target.rootSet.flatMap(pinPathAncestry)]) });
|
|
167
|
+
}
|
|
168
|
+
export function canonicalProspectivePath(path) {
|
|
169
|
+
if (typeof path !== 'string' || !isAbsolute(path) || path.includes('\0') || Buffer.byteLength(path) > 4096)
|
|
170
|
+
throw new DaemonSecurityError('invalid_target', 'Target paths must be bounded absolute paths without NUL.');
|
|
171
|
+
let at = resolve(path);
|
|
172
|
+
const tail = [];
|
|
173
|
+
while (!exists(at)) {
|
|
174
|
+
tail.unshift(at.slice(dirname(at).length + (dirname(at) === sep ? 0 : 1)));
|
|
175
|
+
at = dirname(at);
|
|
176
|
+
}
|
|
177
|
+
return join(realpathSync(at), ...tail);
|
|
178
|
+
}
|
|
179
|
+
export function identityFor(target, instanceId) {
|
|
180
|
+
return { namespaceId: target.namespaceId, instanceId, agentDir: target.agentDir, rootSet: [...target.rootSet] };
|
|
181
|
+
}
|
|
182
|
+
export function protocolTarget(target) {
|
|
183
|
+
return target.kind === 'production' ? { kind: 'production' } : { kind: 'isolated', runtimeDir: target.runtimeDirectory, fixtureRoot: dirname(target.runtimeDirectory) };
|
|
184
|
+
}
|
|
185
|
+
/** Store roots are excluded: a daemon may own more roots than a client declared. */
|
|
186
|
+
export function assertTargetIdentity(target, expected, actual) {
|
|
187
|
+
if ([expected, actual].some(identity => identity.namespaceId !== target.namespaceId || identity.agentDir !== target.agentDir) || expected.instanceId !== actual.instanceId) {
|
|
188
|
+
throw new DaemonSecurityError('target_mismatch', 'Daemon namespace, agent directory or instance differs from the pinned target.');
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=target.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"target.js","sourceRoot":"","sources":["../../src/daemon/target.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { SessionManager } from '@earendil-works/pi-coding-agent';
|
|
2
|
+
import { type OperationResult } from '@felan-ai/session-protocol';
|
|
3
|
+
type TreeEntry = OperationResult<'session.tree'>['entries'][number];
|
|
4
|
+
/** Entries are emitted in Pi's tree order (roots, then children sorted by timestamp) so clients render the same rows. */
|
|
5
|
+
export declare function projectTreeEntries(manager: SessionManager): TreeEntry[];
|
|
6
|
+
export {};
|
|
7
|
+
//# sourceMappingURL=tree.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree.d.ts","sourceRoot":"","sources":["../../src/daemon/tree.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAgB,cAAc,EAAmB,MAAM,iCAAiC,CAAC;AACrG,OAAO,EAAgB,KAAK,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAGhF,KAAK,SAAS,GAAG,eAAe,CAAC,cAAc,CAAC,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;AAKpE,yHAAyH;AACzH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,cAAc,GAAG,SAAS,EAAE,CAUvE"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { homedir } from 'node:os';
|
|
2
|
+
import { stopReasonOf } from '@felan-ai/session-protocol';
|
|
3
|
+
import { boundedText } from './projection.js';
|
|
4
|
+
const maxTextBytes = 16_384;
|
|
5
|
+
/** Entries are emitted in Pi's tree order (roots, then children sorted by timestamp) so clients render the same rows. */
|
|
6
|
+
export function projectTreeEntries(manager) {
|
|
7
|
+
const calls = toolCalls(manager.getEntries());
|
|
8
|
+
const result = [];
|
|
9
|
+
const stack = [...manager.getTree()].reverse();
|
|
10
|
+
while (stack.length) {
|
|
11
|
+
const node = stack.pop();
|
|
12
|
+
result.push(treeEntry(manager, node, calls));
|
|
13
|
+
for (let index = node.children.length - 1; index >= 0; index--)
|
|
14
|
+
stack.push(node.children[index]);
|
|
15
|
+
}
|
|
16
|
+
return result;
|
|
17
|
+
}
|
|
18
|
+
function toolCalls(entries) {
|
|
19
|
+
const calls = new Map();
|
|
20
|
+
for (const entry of entries) {
|
|
21
|
+
if (entry.type !== 'message' || entry.message.role !== 'assistant' || !Array.isArray(entry.message.content))
|
|
22
|
+
continue;
|
|
23
|
+
for (const block of entry.message.content) {
|
|
24
|
+
if (block.type === 'toolCall')
|
|
25
|
+
calls.set(block.id, { name: block.name, arguments: block.arguments });
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return calls;
|
|
29
|
+
}
|
|
30
|
+
function treeEntry(manager, node, calls) {
|
|
31
|
+
const entry = node.entry;
|
|
32
|
+
const parent = entry.parentId && entry.parentId !== entry.id && manager.getEntry(entry.parentId) ? entry.parentId : undefined;
|
|
33
|
+
const labelTimestamp = node.labelTimestamp ? Date.parse(node.labelTimestamp) : NaN;
|
|
34
|
+
const { role, title, stopReason, errorMessage } = display(entry, calls);
|
|
35
|
+
return {
|
|
36
|
+
id: entry.id,
|
|
37
|
+
...(parent ? { parent } : {}),
|
|
38
|
+
kind: entry.type,
|
|
39
|
+
...(role ? { role } : {}),
|
|
40
|
+
...(node.label ? { label: node.label } : {}),
|
|
41
|
+
...(Number.isFinite(labelTimestamp) ? { labelTimestamp: Math.max(0, labelTimestamp) } : {}),
|
|
42
|
+
...(title ? { title: boundedText(title, maxTextBytes) } : {}),
|
|
43
|
+
summary: boundedText(summary(entry), maxTextBytes),
|
|
44
|
+
timestamp: Math.max(0, Date.parse(entry.timestamp) || 0),
|
|
45
|
+
...(stopReason ? { stopReason } : {}),
|
|
46
|
+
...(errorMessage ? { errorMessage: boundedText(errorMessage, maxTextBytes) } : {}),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function display(entry, calls) {
|
|
50
|
+
switch (entry.type) {
|
|
51
|
+
case 'message': {
|
|
52
|
+
const message = entry.message;
|
|
53
|
+
if (message.role === 'toolResult') {
|
|
54
|
+
const call = calls.get(message.toolCallId);
|
|
55
|
+
return { role: message.role, title: call ? formatToolCall(call.name, call.arguments) : message.toolName || 'tool' };
|
|
56
|
+
}
|
|
57
|
+
if (message.role === 'assistant') {
|
|
58
|
+
return { role: message.role, stopReason: stopReasonOf(message.stopReason), errorMessage: message.errorMessage };
|
|
59
|
+
}
|
|
60
|
+
return { role: message.role };
|
|
61
|
+
}
|
|
62
|
+
case 'custom_message': return { title: entry.customType };
|
|
63
|
+
case 'compaction': return { title: `compaction: ${Math.round(entry.tokensBefore / 1000)}k tokens` };
|
|
64
|
+
case 'model_change': return { title: `model: ${entry.modelId}` };
|
|
65
|
+
case 'thinking_level_change': return { title: `thinking: ${entry.thinkingLevel}` };
|
|
66
|
+
case 'custom': return { title: `custom: ${entry.customType}` };
|
|
67
|
+
case 'context_edit': return { title: `context ${entry.replacement === null ? 'omit' : 'replace'}: ${entry.targetId}` };
|
|
68
|
+
case 'label': return { title: `label: ${entry.label ?? '(cleared)'}` };
|
|
69
|
+
case 'session_info': return { title: `title: ${entry.name || 'empty'}` };
|
|
70
|
+
default: return {};
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function summary(entry) {
|
|
74
|
+
switch (entry.type) {
|
|
75
|
+
case 'message':
|
|
76
|
+
if (entry.message.role === 'bashExecution')
|
|
77
|
+
return entry.message.command;
|
|
78
|
+
return 'content' in entry.message ? textOf(entry.message.content) : '';
|
|
79
|
+
case 'custom_message': return textOf(entry.content);
|
|
80
|
+
case 'compaction':
|
|
81
|
+
case 'branch_summary': return entry.summary;
|
|
82
|
+
default: return '';
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function textOf(content) {
|
|
86
|
+
if (typeof content === 'string')
|
|
87
|
+
return content;
|
|
88
|
+
if (!Array.isArray(content))
|
|
89
|
+
return '';
|
|
90
|
+
return content.map(part => part && typeof part === 'object' && 'type' in part && part.type === 'text' && 'text' in part && typeof part.text === 'string' ? part.text : '').join('');
|
|
91
|
+
}
|
|
92
|
+
/** Mirrors Pi's tool-call labels; the client adds the surrounding brackets. */
|
|
93
|
+
function formatToolCall(name, value) {
|
|
94
|
+
const args = value && typeof value === 'object' ? value : {};
|
|
95
|
+
const shortenPath = (path) => {
|
|
96
|
+
const home = homedir();
|
|
97
|
+
return home && path.startsWith(home) ? `~${path.slice(home.length)}` : path;
|
|
98
|
+
};
|
|
99
|
+
switch (name) {
|
|
100
|
+
case 'read': {
|
|
101
|
+
const offset = args.offset;
|
|
102
|
+
const limit = args.limit;
|
|
103
|
+
let display = shortenPath(String(args.path || args.file_path || ''));
|
|
104
|
+
if (offset !== undefined || limit !== undefined) {
|
|
105
|
+
const start = offset ?? 1;
|
|
106
|
+
const end = limit !== undefined ? start + limit - 1 : '';
|
|
107
|
+
display += `:${start}${end ? `-${end}` : ''}`;
|
|
108
|
+
}
|
|
109
|
+
return `read: ${display}`;
|
|
110
|
+
}
|
|
111
|
+
case 'write': return `write: ${shortenPath(String(args.path || args.file_path || ''))}`;
|
|
112
|
+
case 'edit': return `edit: ${shortenPath(String(args.path || args.file_path || ''))}`;
|
|
113
|
+
case 'bash': {
|
|
114
|
+
const raw = String(args.command || '');
|
|
115
|
+
return `bash: ${raw.replace(/[\n\t]/gu, ' ').trim().slice(0, 50)}${raw.length > 50 ? '...' : ''}`;
|
|
116
|
+
}
|
|
117
|
+
case 'grep': return `grep: /${String(args.pattern || '')}/ in ${shortenPath(String(args.path || '.'))}`;
|
|
118
|
+
case 'find': return `find: ${String(args.pattern || '')} in ${shortenPath(String(args.path || '.'))}`;
|
|
119
|
+
case 'ls': return `ls: ${shortenPath(String(args.path || '.'))}`;
|
|
120
|
+
default: {
|
|
121
|
+
const json = JSON.stringify(value) ?? '';
|
|
122
|
+
return `${name}: ${json.slice(0, 40)}${json.length > 40 ? '...' : ''}`;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=tree.js.map
|