@sapiom/harness 0.0.0 → 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/README.md +44 -43
- package/dist/cli/auth.d.ts +26 -0
- package/dist/cli/auth.d.ts.map +1 -0
- package/dist/cli/auth.js +39 -0
- package/dist/cli/auth.js.map +1 -0
- package/dist/cli/bin.d.ts +3 -0
- package/dist/cli/bin.d.ts.map +1 -0
- package/dist/cli/bin.js +163 -0
- package/dist/cli/bin.js.map +1 -0
- package/dist/cli/consent.d.ts +15 -0
- package/dist/cli/consent.d.ts.map +1 -0
- package/dist/cli/consent.js +81 -0
- package/dist/cli/consent.js.map +1 -0
- package/dist/cli/doctor.d.ts +27 -0
- package/dist/cli/doctor.d.ts.map +1 -0
- package/dist/cli/doctor.js +74 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/machine-id.d.ts +19 -0
- package/dist/cli/machine-id.d.ts.map +1 -0
- package/dist/cli/machine-id.js +75 -0
- package/dist/cli/machine-id.js.map +1 -0
- package/dist/cli/paths.d.ts +3 -0
- package/dist/cli/paths.d.ts.map +1 -0
- package/dist/cli/paths.js +11 -0
- package/dist/cli/paths.js.map +1 -0
- package/dist/cli/settings.d.ts +26 -0
- package/dist/cli/settings.d.ts.map +1 -0
- package/dist/cli/settings.js +123 -0
- package/dist/cli/settings.js.map +1 -0
- package/dist/core/adapters/claude-code.d.ts +41 -0
- package/dist/core/adapters/claude-code.d.ts.map +1 -0
- package/dist/core/adapters/claude-code.js +238 -0
- package/dist/core/adapters/claude-code.js.map +1 -0
- package/dist/core/adapters/codex.d.ts +59 -0
- package/dist/core/adapters/codex.d.ts.map +1 -0
- package/dist/core/adapters/codex.js +319 -0
- package/dist/core/adapters/codex.js.map +1 -0
- package/dist/core/canvas-body.d.ts +45 -0
- package/dist/core/canvas-body.d.ts.map +1 -0
- package/dist/core/canvas-body.js +94 -0
- package/dist/core/canvas-body.js.map +1 -0
- package/dist/core/canvas-cache.d.ts +23 -0
- package/dist/core/canvas-cache.d.ts.map +1 -0
- package/dist/core/canvas-cache.js +64 -0
- package/dist/core/canvas-cache.js.map +1 -0
- package/dist/core/canvas-enrich.d.ts +106 -0
- package/dist/core/canvas-enrich.d.ts.map +1 -0
- package/dist/core/canvas-enrich.js +178 -0
- package/dist/core/canvas-enrich.js.map +1 -0
- package/dist/core/canvas-enrichment.d.ts +144 -0
- package/dist/core/canvas-enrichment.d.ts.map +1 -0
- package/dist/core/canvas-enrichment.js +192 -0
- package/dist/core/canvas-enrichment.js.map +1 -0
- package/dist/core/canvas-graph.d.ts +71 -0
- package/dist/core/canvas-graph.d.ts.map +1 -0
- package/dist/core/canvas-graph.js +111 -0
- package/dist/core/canvas-graph.js.map +1 -0
- package/dist/core/canvas-index-classify.d.ts +41 -0
- package/dist/core/canvas-index-classify.d.ts.map +1 -0
- package/dist/core/canvas-index-classify.js +63 -0
- package/dist/core/canvas-index-classify.js.map +1 -0
- package/dist/core/canvas-interconnections.d.ts +24 -0
- package/dist/core/canvas-interconnections.d.ts.map +1 -0
- package/dist/core/canvas-interconnections.js +96 -0
- package/dist/core/canvas-interconnections.js.map +1 -0
- package/dist/core/canvas-manifest-check.d.ts +15 -0
- package/dist/core/canvas-manifest-check.d.ts.map +1 -0
- package/dist/core/canvas-manifest-check.js +90 -0
- package/dist/core/canvas-manifest-check.js.map +1 -0
- package/dist/core/canvas-render.d.ts +73 -0
- package/dist/core/canvas-render.d.ts.map +1 -0
- package/dist/core/canvas-render.js +145 -0
- package/dist/core/canvas-render.js.map +1 -0
- package/dist/core/canvas-svg.d.ts +50 -0
- package/dist/core/canvas-svg.d.ts.map +1 -0
- package/dist/core/canvas-svg.js +240 -0
- package/dist/core/canvas-svg.js.map +1 -0
- package/dist/core/canvas-template.d.ts +43 -0
- package/dist/core/canvas-template.d.ts.map +1 -0
- package/dist/core/canvas-template.js +365 -0
- package/dist/core/canvas-template.js.map +1 -0
- package/dist/core/canvas-watcher.d.ts +25 -0
- package/dist/core/canvas-watcher.d.ts.map +1 -0
- package/dist/core/canvas-watcher.js +144 -0
- package/dist/core/canvas-watcher.js.map +1 -0
- package/dist/core/collector/batcher.d.ts +57 -0
- package/dist/core/collector/batcher.d.ts.map +1 -0
- package/dist/core/collector/batcher.js +143 -0
- package/dist/core/collector/batcher.js.map +1 -0
- package/dist/core/collector/codex-tailer.d.ts +85 -0
- package/dist/core/collector/codex-tailer.d.ts.map +1 -0
- package/dist/core/collector/codex-tailer.js +270 -0
- package/dist/core/collector/codex-tailer.js.map +1 -0
- package/dist/core/collector/normalizer.d.ts +33 -0
- package/dist/core/collector/normalizer.d.ts.map +1 -0
- package/dist/core/collector/normalizer.js +94 -0
- package/dist/core/collector/normalizer.js.map +1 -0
- package/dist/core/collector/seq.d.ts +14 -0
- package/dist/core/collector/seq.d.ts.map +1 -0
- package/dist/core/collector/seq.js +20 -0
- package/dist/core/collector/seq.js.map +1 -0
- package/dist/core/collector/store.d.ts +16 -0
- package/dist/core/collector/store.d.ts.map +1 -0
- package/dist/core/collector/store.js +30 -0
- package/dist/core/collector/store.js.map +1 -0
- package/dist/core/collector/transcript.d.ts +38 -0
- package/dist/core/collector/transcript.d.ts.map +1 -0
- package/dist/core/collector/transcript.js +110 -0
- package/dist/core/collector/transcript.js.map +1 -0
- package/dist/core/event-bus.d.ts +9 -0
- package/dist/core/event-bus.d.ts.map +1 -0
- package/dist/core/event-bus.js +25 -0
- package/dist/core/event-bus.js.map +1 -0
- package/dist/core/example-seed.d.ts +34 -0
- package/dist/core/example-seed.d.ts.map +1 -0
- package/dist/core/example-seed.js +277 -0
- package/dist/core/example-seed.js.map +1 -0
- package/dist/core/inject/claude-settings.d.ts +34 -0
- package/dist/core/inject/claude-settings.d.ts.map +1 -0
- package/dist/core/inject/claude-settings.js +152 -0
- package/dist/core/inject/claude-settings.js.map +1 -0
- package/dist/core/inject/mcp-config.d.ts +26 -0
- package/dist/core/inject/mcp-config.d.ts.map +1 -0
- package/dist/core/inject/mcp-config.js +39 -0
- package/dist/core/inject/mcp-config.js.map +1 -0
- package/dist/core/inject/retention.d.ts +66 -0
- package/dist/core/inject/retention.d.ts.map +1 -0
- package/dist/core/inject/retention.js +119 -0
- package/dist/core/inject/retention.js.map +1 -0
- package/dist/core/inject/system-prompt.d.ts +11 -0
- package/dist/core/inject/system-prompt.d.ts.map +1 -0
- package/dist/core/inject/system-prompt.js +22 -0
- package/dist/core/inject/system-prompt.js.map +1 -0
- package/dist/core/macro-runner.d.ts +36 -0
- package/dist/core/macro-runner.d.ts.map +1 -0
- package/dist/core/macro-runner.js +66 -0
- package/dist/core/macro-runner.js.map +1 -0
- package/dist/core/macros.d.ts +10 -0
- package/dist/core/macros.d.ts.map +1 -0
- package/dist/core/macros.js +59 -0
- package/dist/core/macros.js.map +1 -0
- package/dist/core/path-safety.d.ts +33 -0
- package/dist/core/path-safety.d.ts.map +1 -0
- package/dist/core/path-safety.js +63 -0
- package/dist/core/path-safety.js.map +1 -0
- package/dist/core/paths.d.ts +27 -0
- package/dist/core/paths.d.ts.map +1 -0
- package/dist/core/paths.js +43 -0
- package/dist/core/paths.js.map +1 -0
- package/dist/core/port-detector.d.ts +69 -0
- package/dist/core/port-detector.d.ts.map +1 -0
- package/dist/core/port-detector.js +121 -0
- package/dist/core/port-detector.js.map +1 -0
- package/dist/core/session-manager.d.ts +275 -0
- package/dist/core/session-manager.d.ts.map +1 -0
- package/dist/core/session-manager.js +729 -0
- package/dist/core/session-manager.js.map +1 -0
- package/dist/core/task-manager.d.ts +138 -0
- package/dist/core/task-manager.d.ts.map +1 -0
- package/dist/core/task-manager.js +286 -0
- package/dist/core/task-manager.js.map +1 -0
- package/dist/core/task-stream.d.ts +32 -0
- package/dist/core/task-stream.d.ts.map +1 -0
- package/dist/core/task-stream.js +87 -0
- package/dist/core/task-stream.js.map +1 -0
- package/dist/core/workflow-registry.d.ts +36 -0
- package/dist/core/workflow-registry.d.ts.map +1 -0
- package/dist/core/workflow-registry.js +220 -0
- package/dist/core/workflow-registry.js.map +1 -0
- package/dist/core/workspace-context.d.ts +43 -0
- package/dist/core/workspace-context.d.ts.map +1 -0
- package/dist/core/workspace-context.js +108 -0
- package/dist/core/workspace-context.js.map +1 -0
- package/dist/core/workspace-watcher.d.ts +26 -0
- package/dist/core/workspace-watcher.d.ts.map +1 -0
- package/dist/core/workspace-watcher.js +174 -0
- package/dist/core/workspace-watcher.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/profiles/canvas-guidelines.d.ts +20 -0
- package/dist/profiles/canvas-guidelines.d.ts.map +1 -0
- package/dist/profiles/canvas-guidelines.js +48 -0
- package/dist/profiles/canvas-guidelines.js.map +1 -0
- package/dist/profiles/default.d.ts +10 -0
- package/dist/profiles/default.d.ts.map +1 -0
- package/dist/profiles/default.js +70 -0
- package/dist/profiles/default.js.map +1 -0
- package/dist/server/auth.d.ts +9 -0
- package/dist/server/auth.d.ts.map +1 -0
- package/dist/server/auth.js +28 -0
- package/dist/server/auth.js.map +1 -0
- package/dist/server/canvas-render.d.ts +18 -0
- package/dist/server/canvas-render.d.ts.map +1 -0
- package/dist/server/canvas-render.js +24 -0
- package/dist/server/canvas-render.js.map +1 -0
- package/dist/server/canvas.d.ts +12 -0
- package/dist/server/canvas.d.ts.map +1 -0
- package/dist/server/canvas.js +174 -0
- package/dist/server/canvas.js.map +1 -0
- package/dist/server/events-ws.d.ts +11 -0
- package/dist/server/events-ws.d.ts.map +1 -0
- package/dist/server/events-ws.js +24 -0
- package/dist/server/events-ws.js.map +1 -0
- package/dist/server/fs.d.ts +4 -0
- package/dist/server/fs.d.ts.map +1 -0
- package/dist/server/fs.js +88 -0
- package/dist/server/fs.js.map +1 -0
- package/dist/server/index.d.ts +83 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +0 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/ingest.d.ts +74 -0
- package/dist/server/ingest.d.ts.map +1 -0
- package/dist/server/ingest.js +74 -0
- package/dist/server/ingest.js.map +1 -0
- package/dist/server/macros.d.ts +32 -0
- package/dist/server/macros.d.ts.map +1 -0
- package/dist/server/macros.js +76 -0
- package/dist/server/macros.js.map +1 -0
- package/dist/server/rest.d.ts +75 -0
- package/dist/server/rest.d.ts.map +1 -0
- package/dist/server/rest.js +235 -0
- package/dist/server/rest.js.map +1 -0
- package/dist/server/static.d.ts +8 -0
- package/dist/server/static.d.ts.map +1 -0
- package/dist/server/static.js +36 -0
- package/dist/server/static.js.map +1 -0
- package/dist/server/terminal-ws.d.ts +9 -0
- package/dist/server/terminal-ws.d.ts.map +1 -0
- package/dist/server/terminal-ws.js +59 -0
- package/dist/server/terminal-ws.js.map +1 -0
- package/dist/server/ws-router.d.ts +16 -0
- package/dist/server/ws-router.d.ts.map +1 -0
- package/dist/server/ws-router.js +26 -0
- package/dist/server/ws-router.js.map +1 -0
- package/dist/shared/types.d.ts +485 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/dist/shared/types.js +80 -0
- package/dist/shared/types.js.map +1 -0
- package/dist/web/assets/index-B9R4TzH7.css +32 -0
- package/dist/web/assets/index-Dh97QAgq.js +192 -0
- package/dist/web/index.html +27 -0
- package/package.json +84 -7
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SessionManager — node-pty registry implementing the session lifecycle from
|
|
3
|
+
* the shared contract: create, resume, kill, list. Persists HarnessSession[]
|
|
4
|
+
* to disk (HARNESS_PATHS.sessions) so the SPA's session dropdown survives
|
|
5
|
+
* server restarts, even though the ptys themselves do not.
|
|
6
|
+
*/
|
|
7
|
+
import { type CreateSessionRequest, type HarnessAdapter, type HarnessKind, type HarnessSession, type LaunchOpts } from "../shared/types.js";
|
|
8
|
+
type IPty = import("node-pty").IPty;
|
|
9
|
+
type PtyForkOptions = import("node-pty").IPtyForkOptions;
|
|
10
|
+
export type PtySpawnFn = (file: string, args: string[], options: PtyForkOptions) => IPty;
|
|
11
|
+
/**
|
|
12
|
+
* node-pty ships prebuilt native binaries (including a tiny `spawn-helper`
|
|
13
|
+
* on macOS/Linux) rather than compiling from source. Observed in the wild:
|
|
14
|
+
* a pnpm-managed install can extract that helper without its executable bit
|
|
15
|
+
* set, which fails every single spawn with an opaque "posix_spawnp failed"
|
|
16
|
+
* — nothing to do with the harness's own code, but fatal to every session
|
|
17
|
+
* launch. Best-effort self-heal before the first real spawn; silently a
|
|
18
|
+
* no-op if the file's missing (wrong platform/arch) or already executable.
|
|
19
|
+
* Exported so scripts/e2e-live.ts's preflight check shares this exact fix
|
|
20
|
+
* instead of duplicating it.
|
|
21
|
+
*/
|
|
22
|
+
export declare function ensureSpawnHelperExecutable(): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Thrown by `submitInput()` when a session's pty is alive but never became
|
|
25
|
+
* ready (see `HarnessSession.ready`) within `READY_GRACE_MS` — the trust-
|
|
26
|
+
* dialog race this whole readiness mechanism exists to catch. Callers
|
|
27
|
+
* (rest.ts, macros.ts) catch this specifically and surface it as a 409 with
|
|
28
|
+
* a UI-visible reason, rather than letting it fall into a generic 500 or
|
|
29
|
+
* (worse, the bug this fixes) silently writing into a non-interactive TUI.
|
|
30
|
+
*/
|
|
31
|
+
export declare class SessionNotReadyError extends Error {
|
|
32
|
+
constructor(id: string);
|
|
33
|
+
}
|
|
34
|
+
export type SessionStatusListener = (session: HarnessSession) => void;
|
|
35
|
+
export type SessionDataListener = (chunk: string) => void;
|
|
36
|
+
/** See `onActivity()`. */
|
|
37
|
+
export type SessionActivityListener = (harnessSessionId: string) => void;
|
|
38
|
+
/**
|
|
39
|
+
* Builds the harness-specific part of LaunchOpts (generated system-prompt /
|
|
40
|
+
* mcp-config / settings file paths). SessionManager owns cwd + harnessSessionId;
|
|
41
|
+
* this lets the server layer inject config-file generation (profiles, MCP
|
|
42
|
+
* wiring) without SessionManager needing to know how those files are produced.
|
|
43
|
+
* May return synchronously or a Promise — generating the config files is
|
|
44
|
+
* inherently async (they're written to disk), so `create()`/`resume()` await
|
|
45
|
+
* whichever shape is handed in; existing sync test doubles keep working
|
|
46
|
+
* unchanged (`await` on a plain value just resolves immediately).
|
|
47
|
+
*/
|
|
48
|
+
export type LaunchOptsBuilder = (harnessSessionId: string, req: Pick<CreateSessionRequest, "cwd" | "harness" | "profile">) => Omit<LaunchOpts, "harnessSessionId" | "cwd"> | Promise<Omit<LaunchOpts, "harnessSessionId" | "cwd">>;
|
|
49
|
+
export interface SessionManagerOptions {
|
|
50
|
+
adapters: Partial<Record<HarnessKind, HarnessAdapter>>;
|
|
51
|
+
/** Base URL the harness server is reachable at, e.g. http://127.0.0.1:4100. */
|
|
52
|
+
ingestUrl: string;
|
|
53
|
+
/** Per-boot secret; injected into every session's env so hook scripts can auth to /ingest. */
|
|
54
|
+
ingestToken: string;
|
|
55
|
+
/** Forwarded to sessions as SAPIOM_COLLECTOR_URL when set. */
|
|
56
|
+
collectorUrl?: string;
|
|
57
|
+
/** Absolute path to the session registry file. Defaults to HARNESS_PATHS.sessions (expanded). */
|
|
58
|
+
sessionsPath?: string;
|
|
59
|
+
/** Injectable for tests. Defaults to a lazily-loaded node-pty. */
|
|
60
|
+
spawnPty?: PtySpawnFn;
|
|
61
|
+
buildLaunchOpts?: LaunchOptsBuilder;
|
|
62
|
+
now?: () => string;
|
|
63
|
+
generateId?: () => string;
|
|
64
|
+
/**
|
|
65
|
+
* Writes HARNESS_CONTEXT_FILE for a session — the caller (server/index.ts's
|
|
66
|
+
* `writeSessionContext`) owns resolving the session's `boundWorkflowPath`
|
|
67
|
+
* against the live workflow registry and serializing the full workspace
|
|
68
|
+
* state; this layer just decides *when* to call it. Called unconditionally
|
|
69
|
+
* from `create()`, before the pty is spawned, so every session gets the
|
|
70
|
+
* file regardless of entry point (REST, `autoCreateSession`) — no entry
|
|
71
|
+
* point can skip it by calling `create()` directly. Also used by
|
|
72
|
+
* `resume()` as a backfill when the file is entirely missing (see
|
|
73
|
+
* `workspaceContextExists`). Defaults to a no-op so tests that pass a fake
|
|
74
|
+
* `cwd` (e.g. `/tmp/proj`) never touch the real filesystem unless they opt
|
|
75
|
+
* in.
|
|
76
|
+
*/
|
|
77
|
+
writeWorkspaceContext?: (session: HarnessSession) => Promise<void>;
|
|
78
|
+
/**
|
|
79
|
+
* Reports whether HARNESS_CONTEXT_FILE already exists for a cwd. Used only
|
|
80
|
+
* by `resume()`, to decide whether a backfill write is needed — resume
|
|
81
|
+
* must never clobber a file that could already reflect a real binding.
|
|
82
|
+
* Defaults to `true` (assume it exists, never backfill) to match the
|
|
83
|
+
* no-op default of `writeWorkspaceContext`.
|
|
84
|
+
*/
|
|
85
|
+
workspaceContextExists?: (cwd: string) => Promise<boolean>;
|
|
86
|
+
/**
|
|
87
|
+
* Drops the canvas kit template into `<cwd>/.sapiom/canvas/index.html`
|
|
88
|
+
* when nothing is there yet (backfill-only — the real implementation,
|
|
89
|
+
* `ensureCanvasTemplate` from core/canvas-template.ts, does its own
|
|
90
|
+
* existence check internally, so unlike `writeWorkspaceContext` this
|
|
91
|
+
* needs no separate `*Exists` companion). Called from both `create()` and
|
|
92
|
+
* `resume()` so the canvas pane is never a blank iframe, regardless of
|
|
93
|
+
* entry point. Defaults to a no-op so tests that pass a fake `cwd` never
|
|
94
|
+
* touch the real filesystem unless they opt in.
|
|
95
|
+
*/
|
|
96
|
+
ensureCanvasTemplate?: (cwd: string) => Promise<void>;
|
|
97
|
+
/**
|
|
98
|
+
* Injectable for tests (fake ptys carry fake pids that must never be
|
|
99
|
+
* probed against real OS processes). Defaults to `defaultIsPidAlive`.
|
|
100
|
+
*/
|
|
101
|
+
isPidAlive?: (pid: number) => boolean;
|
|
102
|
+
}
|
|
103
|
+
export declare class SessionManager {
|
|
104
|
+
private readonly adapters;
|
|
105
|
+
private readonly ingestUrl;
|
|
106
|
+
private readonly ingestToken;
|
|
107
|
+
private readonly collectorUrl;
|
|
108
|
+
private readonly sessionsPath;
|
|
109
|
+
private readonly spawnPty;
|
|
110
|
+
private readonly buildLaunchOpts;
|
|
111
|
+
private readonly now;
|
|
112
|
+
private readonly generateId;
|
|
113
|
+
private readonly writeWorkspaceContext;
|
|
114
|
+
private readonly workspaceContextExists;
|
|
115
|
+
private readonly ensureCanvasTemplate;
|
|
116
|
+
private readonly isPidAlive;
|
|
117
|
+
private readonly sessions;
|
|
118
|
+
private readonly ptys;
|
|
119
|
+
private readonly statusEmitter;
|
|
120
|
+
private readonly activityEmitter;
|
|
121
|
+
/** Epoch ms of the last `onActivity` broadcast per session — see `recordActivity()`. */
|
|
122
|
+
private readonly lastActivityBroadcast;
|
|
123
|
+
private writeQueue;
|
|
124
|
+
private writeSeq;
|
|
125
|
+
private initialized;
|
|
126
|
+
constructor(options: SessionManagerOptions);
|
|
127
|
+
/**
|
|
128
|
+
* Loads the persisted registry. Any session left "starting"/"running" from
|
|
129
|
+
* a previous process is marked "exited" — ptys don't survive a restart.
|
|
130
|
+
*/
|
|
131
|
+
init(): Promise<void>;
|
|
132
|
+
list(): HarnessSession[];
|
|
133
|
+
get(id: string): HarnessSession | undefined;
|
|
134
|
+
private getAdapter;
|
|
135
|
+
create(req: CreateSessionRequest): Promise<HarnessSession>;
|
|
136
|
+
/**
|
|
137
|
+
* Registers a purely historical (never-launched-by-this-harness) session so
|
|
138
|
+
* it can subsequently be resumed via `resume()`. Used by the server layer
|
|
139
|
+
* when a user picks a past session out of transcript-scanned history.
|
|
140
|
+
*/
|
|
141
|
+
registerHistorical(input: {
|
|
142
|
+
agentSessionId: string;
|
|
143
|
+
harness: HarnessKind;
|
|
144
|
+
cwd: string;
|
|
145
|
+
title: string;
|
|
146
|
+
lastActiveAt: string;
|
|
147
|
+
}): HarnessSession;
|
|
148
|
+
resume(id: string): Promise<HarnessSession>;
|
|
149
|
+
kill(id: string): boolean;
|
|
150
|
+
/** Kills every currently-live pty. Call this on server shutdown — without
|
|
151
|
+
* it, spawned agent processes (claude/codex) outlive the harness server
|
|
152
|
+
* itself, e.g. after Ctrl+C, since closing the HTTP/WS server doesn't
|
|
153
|
+
* touch unrelated child processes on its own. */
|
|
154
|
+
killAll(): void;
|
|
155
|
+
/**
|
|
156
|
+
* Defensive liveness backstop, run periodically by the server: any
|
|
157
|
+
* non-exited session whose pty process is provably gone gets its exit
|
|
158
|
+
* synthesized. The specific transitions are already reconciled at their
|
|
159
|
+
* source (create/resume pre-pty failures, kill()'s missed-exit fallback),
|
|
160
|
+
* but node-pty has been observed to simply never fire `onExit` for a
|
|
161
|
+
* process that died moments after spawning (see `kill()`) — and a process
|
|
162
|
+
* that dies *on its own* that way has no kill()-style fallback watching
|
|
163
|
+
* it. This sweep is the catch-all for that and any transition not yet
|
|
164
|
+
* root-caused: a stale record shows as a ghost tab (non-exited status, no
|
|
165
|
+
* live pty) until something reconciles it.
|
|
166
|
+
*/
|
|
167
|
+
sweepDeadSessions(): void;
|
|
168
|
+
write(id: string, data: string): boolean;
|
|
169
|
+
/**
|
|
170
|
+
* Inject a discrete prompt (macros, the Visualize button, `/api/sessions/:id/input`)
|
|
171
|
+
* with proper submit semantics — distinct from `write()`, which is a raw
|
|
172
|
+
* passthrough for live keystrokes from the terminal WS and must never add
|
|
173
|
+
* this delay/splitting behavior. See `SUBMIT_DELAY_MS` for why non-empty
|
|
174
|
+
* submitted text can't just be written as `${text}\r` in one call.
|
|
175
|
+
*
|
|
176
|
+
* Gated on readiness (see `HarnessSession.ready` / `isReadyEnough`): a
|
|
177
|
+
* "running" pty can still be sitting on a blocking prompt that swallows
|
|
178
|
+
* whatever's written to it. Briefly waits out `READY_GRACE_MS` for the
|
|
179
|
+
* ordinary "fired a beat too early" case; throws `SessionNotReadyError`
|
|
180
|
+
* — never silently proceeds — if the session still isn't ready after
|
|
181
|
+
* that, so the caller (rest.ts, macros.ts) can surface a clear reason
|
|
182
|
+
* instead of the input just vanishing.
|
|
183
|
+
*/
|
|
184
|
+
submitInput(id: string, text: string, submit?: boolean): Promise<boolean>;
|
|
185
|
+
resize(id: string, cols: number, rows: number): boolean;
|
|
186
|
+
/**
|
|
187
|
+
* Subscribe to a session's output. Replays the retained scrollback buffer
|
|
188
|
+
* synchronously before returning so a reconnecting WS client sees recent
|
|
189
|
+
* output immediately. Returns undefined if the session has no live pty.
|
|
190
|
+
*/
|
|
191
|
+
attach(id: string, listener: SessionDataListener): (() => void) | undefined;
|
|
192
|
+
onStatusChange(listener: SessionStatusListener): () => void;
|
|
193
|
+
/**
|
|
194
|
+
* Subscribe to a session producing terminal output — throttled (see
|
|
195
|
+
* `ACTIVITY_BROADCAST_THROTTLE_MS`), not one event per pty.onData chunk.
|
|
196
|
+
* Fires for every session regardless of whether anything has its
|
|
197
|
+
* /ws/terminal socket open, unlike `attach()`.
|
|
198
|
+
*/
|
|
199
|
+
onActivity(listener: SessionActivityListener): () => void;
|
|
200
|
+
/**
|
|
201
|
+
* Leading-edge throttle: broadcasts immediately on the first byte after a
|
|
202
|
+
* quiet period, then drops everything else for this session until
|
|
203
|
+
* `ACTIVITY_BROADCAST_THROTTLE_MS` has elapsed — a busy TUI's onData fires
|
|
204
|
+
* far more often than that, and callers (the SPA's per-tab pulse) only
|
|
205
|
+
* care that the session is active right now, not each individual chunk.
|
|
206
|
+
*/
|
|
207
|
+
private recordActivity;
|
|
208
|
+
setAgentSessionId(id: string, agentSessionId: string): void;
|
|
209
|
+
/**
|
|
210
|
+
* Marks a session's TUI as genuinely interactive — see `HarnessSession.ready`.
|
|
211
|
+
* Called from the ingest pipeline when a SessionStart(-equivalent) event
|
|
212
|
+
* is processed for this session (real hook for Claude Code, tailer-
|
|
213
|
+
* translated for Codex). Idempotent; a session that's exited or already
|
|
214
|
+
* ready is a silent no-op.
|
|
215
|
+
*/
|
|
216
|
+
setReady(id: string): void;
|
|
217
|
+
/**
|
|
218
|
+
* Whether `id` should be treated as ready to receive programmatic input
|
|
219
|
+
* right now — `session.ready` (the real signal), OR, for a harness that
|
|
220
|
+
* declares `detectBlockingPrompt` (currently: Codex, whose rollout file —
|
|
221
|
+
* and therefore its SessionStart-equivalent — isn't written until the
|
|
222
|
+
* *first* turn is submitted, so the real signal can never arrive before
|
|
223
|
+
* the very first injection that needs it): the pty has had a moment to
|
|
224
|
+
* render its first real frame (`READY_SETTLE_MS`) and that frame doesn't
|
|
225
|
+
* show a known blocking prompt. A harness without `detectBlockingPrompt`
|
|
226
|
+
* (Claude Code) gets no such fallback — its SessionStart hook is reliable
|
|
227
|
+
* standalone, and a scrollback guess would just reopen the exact race
|
|
228
|
+
* this mechanism exists to close.
|
|
229
|
+
*/
|
|
230
|
+
private isReadyEnough;
|
|
231
|
+
/**
|
|
232
|
+
* Polls `isReadyEnough` until it's true, the session's pty goes away
|
|
233
|
+
* (killed/exited — it's never going to become ready now), or `timeoutMs`
|
|
234
|
+
* elapses. Used by `submitInput()` only — `write()` (raw terminal
|
|
235
|
+
* keystrokes) must never wait on this, since a human answering the very
|
|
236
|
+
* prompt this is waiting out is exactly how a session becomes ready.
|
|
237
|
+
*/
|
|
238
|
+
private waitUntilReady;
|
|
239
|
+
/** Waits for all in-flight registry writes to settle. Useful before process
|
|
240
|
+
* shutdown (and in tests that assert against the on-disk registry). */
|
|
241
|
+
flush(): Promise<void>;
|
|
242
|
+
setTitle(id: string, title: string): void;
|
|
243
|
+
/** Binds (or, with `null`, unbinds) the session's current workflow
|
|
244
|
+
* selection. The caller (rest.ts) owns validating `workflowPath` against
|
|
245
|
+
* the workflow registry and mirroring the binding into
|
|
246
|
+
* HARNESS_CONTEXT_FILE — this only updates the in-memory/persisted
|
|
247
|
+
* registry entry and broadcasts the change like any other status update. */
|
|
248
|
+
setBoundWorkflowPath(id: string, workflowPath: string | null): void;
|
|
249
|
+
private spawn;
|
|
250
|
+
/**
|
|
251
|
+
* Transitions a session to "exited". Shared by node-pty's own `onExit`
|
|
252
|
+
* callback and `kill()`'s missed-event fallback (see `kill()`) — both are
|
|
253
|
+
* racing to be the one that reports a given pty's death, so this is
|
|
254
|
+
* idempotent: a stale/duplicate call (`this.ptys.get(id) !== handle`,
|
|
255
|
+
* i.e. this handle was already replaced or already reported exited) is a
|
|
256
|
+
* silent no-op rather than double-transitioning or clobbering a newer
|
|
257
|
+
* session/handle that's since taken its place (e.g. a resume).
|
|
258
|
+
*/
|
|
259
|
+
private markExited;
|
|
260
|
+
/**
|
|
261
|
+
* The single place a session record flips to "exited" — shared by
|
|
262
|
+
* `markExited()` (live-pty deaths), `create()`/`resume()`'s pre-pty
|
|
263
|
+
* failure reconciliation, `kill()`'s stale-record path, and
|
|
264
|
+
* `sweepDeadSessions()`. Returns the persist promise so callers that need
|
|
265
|
+
* the registry durably updated before rethrowing (create/resume) can
|
|
266
|
+
* await it; event-driven callers fire-and-forget it like any other write.
|
|
267
|
+
*/
|
|
268
|
+
private transitionExited;
|
|
269
|
+
private emitStatus;
|
|
270
|
+
/** Serializes writes so overlapping persist() calls can't interleave and
|
|
271
|
+
* corrupt the registry file; a failed write doesn't poison later ones. */
|
|
272
|
+
private persist;
|
|
273
|
+
}
|
|
274
|
+
export {};
|
|
275
|
+
//# sourceMappingURL=session-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../src/core/session-manager.ts"],"names":[],"mappings":"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"}
|