@creativeintelligence/abbie 0.1.6 → 0.1.7
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/bin/dev.js +1 -49
- package/bin/run.js +42 -49
- package/dist/cli/commands/project/add.d.ts +0 -1
- package/dist/cli/commands/project/add.js +16 -52
- package/dist/cli/commands/project/list.js +13 -93
- package/dist/cli/commands/project/remove.d.ts +0 -2
- package/dist/cli/commands/project/remove.js +11 -28
- package/dist/cli/commands/session/list.js +3 -12
- package/dist/cli/commands/session/mark-done.js +1 -7
- package/dist/cli/commands/session/start.d.ts +0 -1
- package/dist/cli/commands/session/start.js +5 -7
- package/dist/lib/active-sessions.d.ts +0 -12
- package/dist/lib/active-sessions.js +6 -175
- package/dist/lib/project-path.d.ts +6 -0
- package/dist/lib/project-path.js +21 -0
- package/dist/lib.d.ts +1 -2
- package/dist/lib.js +2 -4
- package/oclif.manifest.json +2569 -6368
- package/package.json +1 -1
- package/dist/cli/commands/backlog/add.d.ts +0 -22
- package/dist/cli/commands/backlog/add.js +0 -65
- package/dist/cli/commands/backlog/claim.d.ts +0 -19
- package/dist/cli/commands/backlog/claim.js +0 -45
- package/dist/cli/commands/backlog/complete.d.ts +0 -18
- package/dist/cli/commands/backlog/complete.js +0 -42
- package/dist/cli/commands/backlog/list.d.ts +0 -20
- package/dist/cli/commands/backlog/list.js +0 -91
- package/dist/cli/commands/backlog/pick.d.ts +0 -18
- package/dist/cli/commands/backlog/pick.js +0 -42
- package/dist/cli/commands/backlog/sync.d.ts +0 -24
- package/dist/cli/commands/backlog/sync.js +0 -109
- package/dist/cli/commands/daemon.d.ts +0 -56
- package/dist/cli/commands/daemon.js +0 -1465
- package/dist/cli/commands/docs/lint.d.ts +0 -18
- package/dist/cli/commands/docs/lint.js +0 -82
- package/dist/cli/commands/docs/sync.d.ts +0 -19
- package/dist/cli/commands/docs/sync.js +0 -76
- package/dist/cli/commands/gc.d.ts +0 -29
- package/dist/cli/commands/gc.js +0 -211
- package/dist/cli/commands/index.d.ts +0 -36
- package/dist/cli/commands/index.js +0 -228
- package/dist/cli/commands/panes/broker.d.ts +0 -17
- package/dist/cli/commands/panes/broker.js +0 -57
- package/dist/cli/commands/panes/pipe-sink.d.ts +0 -17
- package/dist/cli/commands/panes/pipe-sink.js +0 -90
- package/dist/cli/commands/panes/snapshot.d.ts +0 -20
- package/dist/cli/commands/panes/snapshot.js +0 -125
- package/dist/cli/commands/preview/init.d.ts +0 -25
- package/dist/cli/commands/preview/init.js +0 -159
- package/dist/cli/commands/preview/sync.d.ts +0 -23
- package/dist/cli/commands/preview/sync.js +0 -144
- package/dist/cli/commands/preview/watch.d.ts +0 -24
- package/dist/cli/commands/preview/watch.js +0 -153
- package/dist/cli/commands/resource/acquire.d.ts +0 -21
- package/dist/cli/commands/resource/acquire.js +0 -90
- package/dist/cli/commands/resource/list.d.ts +0 -15
- package/dist/cli/commands/resource/list.js +0 -61
- package/dist/cli/commands/resource/release.d.ts +0 -18
- package/dist/cli/commands/resource/release.js +0 -50
- package/dist/cli/commands/resource/wait.d.ts +0 -21
- package/dist/cli/commands/resource/wait.js +0 -73
- package/dist/cli/commands/session/view.d.ts +0 -24
- package/dist/cli/commands/session/view.js +0 -145
- package/dist/cli/commands/start.d.ts +0 -37
- package/dist/cli/commands/start.js +0 -234
- package/dist/cli/commands/triage/claim.d.ts +0 -23
- package/dist/cli/commands/triage/claim.js +0 -186
- package/dist/cli/commands/triage/list.d.ts +0 -22
- package/dist/cli/commands/triage/list.js +0 -112
- package/dist/cli/commands/triage/next.d.ts +0 -18
- package/dist/cli/commands/triage/next.js +0 -63
- package/dist/cli/commands/triage/pull.d.ts +0 -19
- package/dist/cli/commands/triage/pull.js +0 -82
- package/dist/cli/commands/triage/stats.d.ts +0 -16
- package/dist/cli/commands/triage/stats.js +0 -69
- package/dist/cli/commands/tunnel/list.d.ts +0 -16
- package/dist/cli/commands/tunnel/list.js +0 -98
- package/dist/cli/commands/tunnel/start.d.ts +0 -24
- package/dist/cli/commands/tunnel/start.js +0 -107
- package/dist/cli/commands/tunnel/stop.d.ts +0 -20
- package/dist/cli/commands/tunnel/stop.js +0 -90
- package/dist/cli/commands/tunnel/url.d.ts +0 -21
- package/dist/cli/commands/tunnel/url.js +0 -70
- package/dist/cli/commands/windows/context.d.ts +0 -18
- package/dist/cli/commands/windows/context.js +0 -326
- package/dist/cli/commands/windows/focus.d.ts +0 -17
- package/dist/cli/commands/windows/focus.js +0 -103
- package/dist/cli/commands/windows/list.d.ts +0 -21
- package/dist/cli/commands/windows/list.js +0 -172
- package/dist/cli/commands/windows/map.d.ts +0 -17
- package/dist/cli/commands/windows/map.js +0 -168
- package/dist/cli/commands/windows/read.d.ts +0 -21
- package/dist/cli/commands/windows/read.js +0 -241
- package/dist/cli/commands/windows/search.d.ts +0 -24
- package/dist/cli/commands/windows/search.js +0 -171
- package/dist/cli/commands/windows/show.d.ts +0 -19
- package/dist/cli/commands/windows/show.js +0 -165
- package/dist/cli/commands/windows/watch.d.ts +0 -19
- package/dist/cli/commands/windows/watch.js +0 -241
- package/dist/lib/managed-session.d.ts +0 -27
- package/dist/lib/managed-session.js +0 -105
- package/dist/lib/panes/broker.d.ts +0 -130
- package/dist/lib/panes/broker.js +0 -97
- package/dist/lib/panes/index.d.ts +0 -2
- package/dist/lib/panes/index.js +0 -1
- package/dist/lib/panes/server.d.ts +0 -17
- package/dist/lib/panes/server.js +0 -308
- package/dist/lib/preview/manager.d.ts +0 -77
- package/dist/lib/preview/manager.js +0 -369
- package/dist/lib/preview/schema.d.ts +0 -2
- package/dist/lib/preview/schema.js +0 -32
- package/dist/lib/preview/sprite.d.ts +0 -85
- package/dist/lib/preview/sprite.js +0 -321
- package/dist/lib/preview/watcher.d.ts +0 -63
- package/dist/lib/preview/watcher.js +0 -185
- package/dist/lib/project-identity.d.ts +0 -16
- package/dist/lib/project-identity.js +0 -75
- package/dist/lib/tmux/bridge.d.ts +0 -133
- package/dist/lib/tmux/bridge.js +0 -315
- package/dist/lib/tmux/context.d.ts +0 -82
- package/dist/lib/tmux/context.js +0 -239
- package/dist/lib/tmux/index.d.ts +0 -8
- package/dist/lib/tmux/index.js +0 -11
- package/dist/lib/tmux/map.d.ts +0 -57
- package/dist/lib/tmux/map.js +0 -198
- package/dist/lib/tmux/panes.d.ts +0 -27
- package/dist/lib/tmux/panes.js +0 -151
- package/dist/lib/tmux/redaction.d.ts +0 -57
- package/dist/lib/tmux/redaction.js +0 -152
- package/dist/lib/web/analytics.d.ts +0 -63
- package/dist/lib/web/analytics.js +0 -168
- package/dist/lib/web/server.d.ts +0 -26
- package/dist/lib/web/server.js +0 -697
- package/dist/lib/web/tmux-bridge.d.ts +0 -7
- package/dist/lib/web/tmux-bridge.js +0 -7
- package/dist/lib/windows/index.d.ts +0 -3
- package/dist/lib/windows/index.js +0 -2
- package/dist/lib/windows/inventory.d.ts +0 -21
- package/dist/lib/windows/inventory.js +0 -263
- package/dist/lib/windows/types.d.ts +0 -46
- package/dist/lib/windows/types.js +0 -1
package/dist/lib/panes/broker.js
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
import { randomUUID } from "node:crypto";
|
|
2
|
-
import { mkdirSync } from "node:fs";
|
|
3
|
-
import { createConnection } from "node:net";
|
|
4
|
-
import { homedir } from "node:os";
|
|
5
|
-
import { dirname, join } from "node:path";
|
|
6
|
-
export function getDefaultPanesBrokerSocketPath() {
|
|
7
|
-
const runtimeDir = process.env.XDG_RUNTIME_DIR;
|
|
8
|
-
if (runtimeDir)
|
|
9
|
-
return join(runtimeDir, "abbie-panes-broker.sock");
|
|
10
|
-
const home = homedir() || process.env.HOME || "~";
|
|
11
|
-
return join(home, ".abbie", "run", "panes-broker.sock");
|
|
12
|
-
}
|
|
13
|
-
function ensureSocketDir(path) {
|
|
14
|
-
const dir = dirname(path);
|
|
15
|
-
mkdirSync(dir, { recursive: true });
|
|
16
|
-
}
|
|
17
|
-
function nowIso() {
|
|
18
|
-
return new Date().toISOString();
|
|
19
|
-
}
|
|
20
|
-
export function createNdjsonLineParser() {
|
|
21
|
-
let buf = "";
|
|
22
|
-
let onMessageFn = null;
|
|
23
|
-
let onErrorFn = null;
|
|
24
|
-
return {
|
|
25
|
-
pushChunk(chunk) {
|
|
26
|
-
buf += chunk.toString();
|
|
27
|
-
for (;;) {
|
|
28
|
-
const idx = buf.indexOf("\n");
|
|
29
|
-
if (idx === -1)
|
|
30
|
-
break;
|
|
31
|
-
const line = buf.slice(0, idx).trimEnd();
|
|
32
|
-
buf = buf.slice(idx + 1);
|
|
33
|
-
if (!line)
|
|
34
|
-
continue;
|
|
35
|
-
try {
|
|
36
|
-
const msg = JSON.parse(line);
|
|
37
|
-
onMessageFn?.(msg);
|
|
38
|
-
}
|
|
39
|
-
catch (err) {
|
|
40
|
-
onErrorFn?.(new Error(err instanceof Error ? err.message : "Failed to parse NDJSON line"));
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
},
|
|
44
|
-
onMessage(fn) {
|
|
45
|
-
onMessageFn = fn;
|
|
46
|
-
},
|
|
47
|
-
onError(fn) {
|
|
48
|
-
onErrorFn = fn;
|
|
49
|
-
},
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
export function connectPanesBroker(opts = {}, handlers) {
|
|
53
|
-
const socketPath = opts.socketPath ?? getDefaultPanesBrokerSocketPath();
|
|
54
|
-
ensureSocketDir(socketPath);
|
|
55
|
-
const socket = createConnection({ path: socketPath });
|
|
56
|
-
const parser = createNdjsonLineParser();
|
|
57
|
-
parser.onMessage((msg) => handlers?.onMessage?.(msg));
|
|
58
|
-
parser.onError((err) => handlers?.onError?.(err));
|
|
59
|
-
socket.on("data", (chunk) => parser.pushChunk(chunk));
|
|
60
|
-
socket.on("error", (err) => handlers?.onError?.(err instanceof Error ? err : new Error(String(err))));
|
|
61
|
-
socket.on("close", () => handlers?.onClose?.());
|
|
62
|
-
const clientId = randomUUID();
|
|
63
|
-
const send = (msg) => {
|
|
64
|
-
socket.write(`${JSON.stringify(msg)}\n`);
|
|
65
|
-
};
|
|
66
|
-
// Send hello immediately; server can ignore if not required.
|
|
67
|
-
send({
|
|
68
|
-
type: "client.hello",
|
|
69
|
-
at: nowIso(),
|
|
70
|
-
clientId,
|
|
71
|
-
version: 1,
|
|
72
|
-
pid: process.pid,
|
|
73
|
-
});
|
|
74
|
-
const subscribe = (sub) => {
|
|
75
|
-
const requestId = sub.requestId ?? randomUUID();
|
|
76
|
-
send({
|
|
77
|
-
type: "panes.subscribe",
|
|
78
|
-
at: nowIso(),
|
|
79
|
-
requestId,
|
|
80
|
-
target: sub.target,
|
|
81
|
-
redaction: sub.redaction ?? "raw",
|
|
82
|
-
encoding: sub.encoding ?? "text",
|
|
83
|
-
history: sub.history,
|
|
84
|
-
follow: sub.follow ?? true,
|
|
85
|
-
});
|
|
86
|
-
return requestId;
|
|
87
|
-
};
|
|
88
|
-
const unsubscribe = (requestId) => {
|
|
89
|
-
send({ type: "panes.unsubscribe", at: nowIso(), requestId });
|
|
90
|
-
};
|
|
91
|
-
const ping = () => {
|
|
92
|
-
const nonce = randomUUID();
|
|
93
|
-
send({ type: "client.ping", at: nowIso(), nonce });
|
|
94
|
-
return nonce;
|
|
95
|
-
};
|
|
96
|
-
return { socket, clientId, send, subscribe, unsubscribe, ping };
|
|
97
|
-
}
|
package/dist/lib/panes/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./broker.js";
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { type Server } from "node:net";
|
|
2
|
-
type BrokerOptions = {
|
|
3
|
-
socketPath?: string;
|
|
4
|
-
fps?: number;
|
|
5
|
-
forcePipe?: boolean;
|
|
6
|
-
};
|
|
7
|
-
export declare function startPanesBroker(opts: BrokerOptions, ctx: {
|
|
8
|
-
agentsBinPath: string;
|
|
9
|
-
logInfo: (msg: string) => void;
|
|
10
|
-
logWarn: (msg: string) => void;
|
|
11
|
-
}): Promise<{
|
|
12
|
-
socketPath: string;
|
|
13
|
-
server: Server;
|
|
14
|
-
stop: () => Promise<void>;
|
|
15
|
-
}>;
|
|
16
|
-
export {};
|
|
17
|
-
//# sourceMappingURL=server.d.ts.map
|
package/dist/lib/panes/server.js
DELETED
|
@@ -1,308 +0,0 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, unlinkSync } from "node:fs";
|
|
2
|
-
import { createServer } from "node:net";
|
|
3
|
-
import { dirname } from "node:path";
|
|
4
|
-
import { capturePaneScreen, ensurePipePane, getPaneMetrics } from "../tmux/panes.js";
|
|
5
|
-
import * as windows from "../windows/index.js";
|
|
6
|
-
import { createNdjsonLineParser, getDefaultPanesBrokerSocketPath, } from "./broker.js";
|
|
7
|
-
function nowIso() {
|
|
8
|
-
return new Date().toISOString();
|
|
9
|
-
}
|
|
10
|
-
function ensureDirForSocket(socketPath) {
|
|
11
|
-
mkdirSync(dirname(socketPath), { recursive: true });
|
|
12
|
-
}
|
|
13
|
-
function safeUnlinkSocket(socketPath) {
|
|
14
|
-
try {
|
|
15
|
-
if (existsSync(socketPath))
|
|
16
|
-
unlinkSync(socketPath);
|
|
17
|
-
}
|
|
18
|
-
catch {
|
|
19
|
-
// ignore
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
function send(socket, msg) {
|
|
23
|
-
socket.write(`${JSON.stringify(msg)}\n`);
|
|
24
|
-
}
|
|
25
|
-
function getRefFromTarget(target) {
|
|
26
|
-
if (typeof target !== "object" || target === null)
|
|
27
|
-
return null;
|
|
28
|
-
const record = target;
|
|
29
|
-
return typeof record.ref === "string" ? record.ref : null;
|
|
30
|
-
}
|
|
31
|
-
function parseTargetToPaneId(target) {
|
|
32
|
-
if (typeof target !== "object" || target === null)
|
|
33
|
-
return { error: "Invalid target" };
|
|
34
|
-
const maybe = target;
|
|
35
|
-
const paneId = typeof maybe.paneId === "string" ? maybe.paneId : undefined;
|
|
36
|
-
const ref = typeof maybe.ref === "string" ? maybe.ref : undefined;
|
|
37
|
-
if (paneId)
|
|
38
|
-
return { paneId };
|
|
39
|
-
if (!ref)
|
|
40
|
-
return { error: "Missing target.paneId or target.ref" };
|
|
41
|
-
if (ref.startsWith("%"))
|
|
42
|
-
return { paneId: ref };
|
|
43
|
-
return { paneId: undefined, error: "Ref must be a pane id (e.g. %3) or resolved via windows" };
|
|
44
|
-
}
|
|
45
|
-
export async function startPanesBroker(opts, ctx) {
|
|
46
|
-
const socketPath = opts.socketPath ?? getDefaultPanesBrokerSocketPath();
|
|
47
|
-
ensureDirForSocket(socketPath);
|
|
48
|
-
safeUnlinkSocket(socketPath);
|
|
49
|
-
const clients = new Map();
|
|
50
|
-
const subs = new Map();
|
|
51
|
-
const panes = new Map();
|
|
52
|
-
const fps = Math.max(1, Math.min(60, opts.fps ?? 30));
|
|
53
|
-
const frameMs = Math.floor(1000 / fps);
|
|
54
|
-
const server = createServer((socket) => {
|
|
55
|
-
const clientId = `c_${Math.random().toString(16).slice(2)}`;
|
|
56
|
-
const client = { socket, id: clientId, kind: "ui" };
|
|
57
|
-
clients.set(clientId, client);
|
|
58
|
-
const hello = {
|
|
59
|
-
type: "broker.hello",
|
|
60
|
-
at: nowIso(),
|
|
61
|
-
version: 1,
|
|
62
|
-
pid: process.pid,
|
|
63
|
-
};
|
|
64
|
-
send(socket, hello);
|
|
65
|
-
const parser = createNdjsonLineParser();
|
|
66
|
-
socket.on("data", (chunk) => parser.pushChunk(chunk));
|
|
67
|
-
socket.on("close", () => {
|
|
68
|
-
// Drop subscriptions
|
|
69
|
-
for (const [requestId, sub] of subs) {
|
|
70
|
-
if (sub.clientId !== clientId)
|
|
71
|
-
continue;
|
|
72
|
-
subs.delete(requestId);
|
|
73
|
-
const pane = panes.get(sub.paneId);
|
|
74
|
-
pane?.subs.delete(requestId);
|
|
75
|
-
}
|
|
76
|
-
// If pipe client, detach
|
|
77
|
-
if (client.kind === "pipe" && client.paneId) {
|
|
78
|
-
const pane = panes.get(client.paneId);
|
|
79
|
-
if (pane?.pipeClientId === clientId)
|
|
80
|
-
pane.pipeClientId = undefined;
|
|
81
|
-
if (pane?.controllerClientId === clientId)
|
|
82
|
-
pane.controllerClientId = undefined;
|
|
83
|
-
}
|
|
84
|
-
clients.delete(clientId);
|
|
85
|
-
});
|
|
86
|
-
parser.onMessage(async (msg) => {
|
|
87
|
-
const type = typeof msg.type === "string" ? msg.type : "";
|
|
88
|
-
if (type === "client.ping") {
|
|
89
|
-
const nonce = typeof msg.nonce === "string" ? msg.nonce : "";
|
|
90
|
-
send(socket, { type: "broker.pong", at: nowIso(), nonce });
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
if (type === "client.hello") {
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
if (type === "panes.pipe.hello") {
|
|
97
|
-
const paneId = typeof msg.paneId === "string" ? msg.paneId : undefined;
|
|
98
|
-
if (!paneId)
|
|
99
|
-
return;
|
|
100
|
-
client.kind = "pipe";
|
|
101
|
-
client.paneId = paneId;
|
|
102
|
-
const pane = panes.get(paneId) ?? { paneId, dirty: true, lastEmitAt: 0, subs: new Set() };
|
|
103
|
-
pane.pipeClientId = clientId;
|
|
104
|
-
panes.set(paneId, pane);
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
if (type === "panes.pipe.chunk") {
|
|
108
|
-
const paneId = typeof msg.paneId === "string" ? msg.paneId : undefined;
|
|
109
|
-
if (!paneId)
|
|
110
|
-
return;
|
|
111
|
-
const pane = panes.get(paneId) ?? { paneId, dirty: true, lastEmitAt: 0, subs: new Set() };
|
|
112
|
-
pane.dirty = true;
|
|
113
|
-
panes.set(paneId, pane);
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
|
-
if (type === "panes.subscribe") {
|
|
117
|
-
const requestId = typeof msg.requestId === "string" ? msg.requestId : undefined;
|
|
118
|
-
const target = msg.target;
|
|
119
|
-
if (!requestId)
|
|
120
|
-
return;
|
|
121
|
-
// Resolve paneId
|
|
122
|
-
let paneId;
|
|
123
|
-
const parsed = parseTargetToPaneId(target);
|
|
124
|
-
paneId = parsed.paneId;
|
|
125
|
-
// If we got a non-pane-id ref (session:window.pane), resolve via windows inventory.
|
|
126
|
-
const ref = getRefFromTarget(target);
|
|
127
|
-
if (!paneId && ref) {
|
|
128
|
-
const state = await windows.getWindowState(ref, {
|
|
129
|
-
includeNvim: false,
|
|
130
|
-
includeAgent: false,
|
|
131
|
-
includeBuffers: false,
|
|
132
|
-
});
|
|
133
|
-
paneId = state?.window.paneId ?? undefined;
|
|
134
|
-
}
|
|
135
|
-
if (!paneId) {
|
|
136
|
-
const status = {
|
|
137
|
-
type: "panes.status",
|
|
138
|
-
at: nowIso(),
|
|
139
|
-
requestId,
|
|
140
|
-
level: "error",
|
|
141
|
-
message: parsed.error ?? "Failed to resolve paneId",
|
|
142
|
-
};
|
|
143
|
-
send(socket, status);
|
|
144
|
-
return;
|
|
145
|
-
}
|
|
146
|
-
const encoding = msg.encoding === "ansi" ? "ansi" : "text";
|
|
147
|
-
const redaction = msg.redaction === "default" ? "default" : "raw";
|
|
148
|
-
const follow = msg.follow !== false;
|
|
149
|
-
subs.set(requestId, {
|
|
150
|
-
requestId,
|
|
151
|
-
clientId,
|
|
152
|
-
paneId,
|
|
153
|
-
encoding,
|
|
154
|
-
redaction,
|
|
155
|
-
follow,
|
|
156
|
-
active: true,
|
|
157
|
-
});
|
|
158
|
-
const pane = panes.get(paneId) ?? { paneId, dirty: true, lastEmitAt: 0, subs: new Set() };
|
|
159
|
-
pane.subs.add(requestId);
|
|
160
|
-
panes.set(paneId, pane);
|
|
161
|
-
// Ensure pipe-pane is attached (best-effort). The pipe-sink provides
|
|
162
|
-
// event-driven invalidation + raw input injection (bidirectional pipe).
|
|
163
|
-
const sinkCommand = `${ctx.agentsBinPath} panes pipe-sink --pane ${paneId} --sock ${socketPath}`;
|
|
164
|
-
const attached = await ensurePipePane(paneId, sinkCommand, {
|
|
165
|
-
onlyIfUnset: !opts.forcePipe,
|
|
166
|
-
bidirectional: true,
|
|
167
|
-
});
|
|
168
|
-
if (!attached.attached) {
|
|
169
|
-
ctx.logWarn(`pipe-pane attach failed for ${paneId}: ${attached.error ?? "unknown"}`);
|
|
170
|
-
}
|
|
171
|
-
// Send an initial snapshot immediately.
|
|
172
|
-
pane.dirty = true;
|
|
173
|
-
await emitSnapshotForPane(paneId);
|
|
174
|
-
return;
|
|
175
|
-
}
|
|
176
|
-
if (type === "panes.unsubscribe") {
|
|
177
|
-
const requestId = typeof msg.requestId === "string" ? msg.requestId : undefined;
|
|
178
|
-
if (!requestId)
|
|
179
|
-
return;
|
|
180
|
-
const sub = subs.get(requestId);
|
|
181
|
-
if (!sub)
|
|
182
|
-
return;
|
|
183
|
-
subs.delete(requestId);
|
|
184
|
-
panes.get(sub.paneId)?.subs.delete(requestId);
|
|
185
|
-
return;
|
|
186
|
-
}
|
|
187
|
-
if (type === "panes.control.claim") {
|
|
188
|
-
const paneId = typeof msg.paneId === "string" ? msg.paneId : undefined;
|
|
189
|
-
if (!paneId)
|
|
190
|
-
return;
|
|
191
|
-
const pane = panes.get(paneId) ?? { paneId, dirty: false, lastEmitAt: 0, subs: new Set() };
|
|
192
|
-
panes.set(paneId, pane);
|
|
193
|
-
if (pane.controllerClientId && pane.controllerClientId !== clientId) {
|
|
194
|
-
send(socket, {
|
|
195
|
-
type: "panes.status",
|
|
196
|
-
at: nowIso(),
|
|
197
|
-
paneId,
|
|
198
|
-
level: "warn",
|
|
199
|
-
message: "Control already claimed by another client",
|
|
200
|
-
});
|
|
201
|
-
return;
|
|
202
|
-
}
|
|
203
|
-
pane.controllerClientId = clientId;
|
|
204
|
-
send(socket, { type: "panes.status", at: nowIso(), paneId, level: "info", message: "ok" });
|
|
205
|
-
return;
|
|
206
|
-
}
|
|
207
|
-
if (type === "panes.control.release") {
|
|
208
|
-
const paneId = typeof msg.paneId === "string" ? msg.paneId : undefined;
|
|
209
|
-
if (!paneId)
|
|
210
|
-
return;
|
|
211
|
-
const pane = panes.get(paneId);
|
|
212
|
-
if (pane?.controllerClientId === clientId)
|
|
213
|
-
pane.controllerClientId = undefined;
|
|
214
|
-
return;
|
|
215
|
-
}
|
|
216
|
-
if (type === "panes.input") {
|
|
217
|
-
const paneId = typeof msg.paneId === "string" ? msg.paneId : undefined;
|
|
218
|
-
const data = typeof msg.data === "string" ? msg.data : undefined;
|
|
219
|
-
if (!paneId || !data)
|
|
220
|
-
return;
|
|
221
|
-
const pane = panes.get(paneId);
|
|
222
|
-
if (pane?.controllerClientId && pane.controllerClientId !== clientId)
|
|
223
|
-
return;
|
|
224
|
-
if (!pane?.pipeClientId)
|
|
225
|
-
return;
|
|
226
|
-
const pipeClient = clients.get(pane.pipeClientId);
|
|
227
|
-
if (!pipeClient)
|
|
228
|
-
return;
|
|
229
|
-
send(pipeClient.socket, { type: "panes.pipe.input", at: nowIso(), paneId, data });
|
|
230
|
-
return;
|
|
231
|
-
}
|
|
232
|
-
});
|
|
233
|
-
parser.onError(() => {
|
|
234
|
-
// ignore parse errors
|
|
235
|
-
});
|
|
236
|
-
});
|
|
237
|
-
const emitSnapshotForPane = async (paneId) => {
|
|
238
|
-
const pane = panes.get(paneId);
|
|
239
|
-
if (!pane)
|
|
240
|
-
return;
|
|
241
|
-
if (pane.subs.size === 0)
|
|
242
|
-
return;
|
|
243
|
-
const metrics = await getPaneMetrics(paneId);
|
|
244
|
-
const rows = metrics?.rows ?? 24;
|
|
245
|
-
const cols = metrics?.cols ?? 80;
|
|
246
|
-
// Use the first subscription's encoding as the capture mode; if there are
|
|
247
|
-
// mixed encodings, we will send snapshots per-sub below.
|
|
248
|
-
const byRequest = [];
|
|
249
|
-
for (const requestId of pane.subs) {
|
|
250
|
-
const sub = subs.get(requestId);
|
|
251
|
-
if (sub?.active)
|
|
252
|
-
byRequest.push(sub);
|
|
253
|
-
}
|
|
254
|
-
if (byRequest.length === 0)
|
|
255
|
-
return;
|
|
256
|
-
const captureAnsi = byRequest.some((s) => s.encoding === "ansi");
|
|
257
|
-
const screen = await capturePaneScreen(paneId, {
|
|
258
|
-
ansi: captureAnsi,
|
|
259
|
-
rows,
|
|
260
|
-
cursor: metrics
|
|
261
|
-
? { x: metrics.cursorX, y: metrics.cursorY, visible: metrics.cursorFlag !== 0 }
|
|
262
|
-
: undefined,
|
|
263
|
-
});
|
|
264
|
-
// biome-ignore lint/complexity/useRegexLiterals: Regex literal with \u001b triggers Biome control-char lint.
|
|
265
|
-
const sgrRegex = new RegExp("\\u001b\\[[0-9;]*m", "g");
|
|
266
|
-
for (const sub of byRequest) {
|
|
267
|
-
const client = clients.get(sub.clientId);
|
|
268
|
-
if (!client)
|
|
269
|
-
continue;
|
|
270
|
-
const content = sub.encoding === "ansi" ? screen : screen.replace(sgrRegex, "");
|
|
271
|
-
const snapshot = {
|
|
272
|
-
type: "panes.snapshot",
|
|
273
|
-
at: nowIso(),
|
|
274
|
-
requestId: sub.requestId,
|
|
275
|
-
paneId,
|
|
276
|
-
encoding: sub.encoding,
|
|
277
|
-
redaction: sub.redaction,
|
|
278
|
-
cols,
|
|
279
|
-
rows,
|
|
280
|
-
content,
|
|
281
|
-
};
|
|
282
|
-
send(client.socket, snapshot);
|
|
283
|
-
}
|
|
284
|
-
};
|
|
285
|
-
const interval = setInterval(async () => {
|
|
286
|
-
const now = Date.now();
|
|
287
|
-
for (const pane of panes.values()) {
|
|
288
|
-
if (!pane.dirty)
|
|
289
|
-
continue;
|
|
290
|
-
if (now - pane.lastEmitAt < frameMs)
|
|
291
|
-
continue;
|
|
292
|
-
pane.dirty = false;
|
|
293
|
-
pane.lastEmitAt = now;
|
|
294
|
-
await emitSnapshotForPane(pane.paneId);
|
|
295
|
-
}
|
|
296
|
-
}, Math.max(10, Math.floor(frameMs / 2)));
|
|
297
|
-
await new Promise((resolve, reject) => {
|
|
298
|
-
server.once("error", reject);
|
|
299
|
-
server.listen(socketPath, () => resolve());
|
|
300
|
-
});
|
|
301
|
-
ctx.logInfo(`panes broker listening: ${socketPath} (${fps}fps)`);
|
|
302
|
-
const stop = async () => {
|
|
303
|
-
clearInterval(interval);
|
|
304
|
-
await new Promise((resolve) => server.close(() => resolve()));
|
|
305
|
-
safeUnlinkSocket(socketPath);
|
|
306
|
-
};
|
|
307
|
-
return { socketPath, server, stop };
|
|
308
|
-
}
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import { Database } from "bun:sqlite";
|
|
2
|
-
export type DeploymentStatus = "pending" | "syncing" | "installing" | "starting" | "running" | "stopped" | "failed";
|
|
3
|
-
export interface SpriteRecord {
|
|
4
|
-
id: number;
|
|
5
|
-
project_name: string;
|
|
6
|
-
project_path: string;
|
|
7
|
-
sprite_name: string;
|
|
8
|
-
sprite_url: string | null;
|
|
9
|
-
doppler_project: string | null;
|
|
10
|
-
dev_command: string;
|
|
11
|
-
port: number;
|
|
12
|
-
created_at: string;
|
|
13
|
-
updated_at: string;
|
|
14
|
-
}
|
|
15
|
-
export interface DeploymentRecord {
|
|
16
|
-
id: number;
|
|
17
|
-
sprite_id: number;
|
|
18
|
-
status: DeploymentStatus;
|
|
19
|
-
preview_url: string | null;
|
|
20
|
-
screenshot_path: string | null;
|
|
21
|
-
started_at: string;
|
|
22
|
-
stopped_at: string | null;
|
|
23
|
-
error: string | null;
|
|
24
|
-
sync_duration_ms: number | null;
|
|
25
|
-
install_duration_ms: number | null;
|
|
26
|
-
start_duration_ms: number | null;
|
|
27
|
-
}
|
|
28
|
-
export interface RegisterSpriteOptions {
|
|
29
|
-
spriteUrl?: string;
|
|
30
|
-
dopplerProject?: string;
|
|
31
|
-
devCommand?: string;
|
|
32
|
-
port?: number;
|
|
33
|
-
}
|
|
34
|
-
export interface RecordDeploymentOptions {
|
|
35
|
-
previewUrl?: string;
|
|
36
|
-
screenshotPath?: string;
|
|
37
|
-
error?: string;
|
|
38
|
-
syncDurationMs?: number;
|
|
39
|
-
installDurationMs?: number;
|
|
40
|
-
startDurationMs?: number;
|
|
41
|
-
}
|
|
42
|
-
export interface UpdateDeploymentOptions {
|
|
43
|
-
status?: DeploymentStatus;
|
|
44
|
-
previewUrl?: string;
|
|
45
|
-
screenshotPath?: string;
|
|
46
|
-
stoppedAt?: string;
|
|
47
|
-
error?: string;
|
|
48
|
-
syncDurationMs?: number;
|
|
49
|
-
installDurationMs?: number;
|
|
50
|
-
startDurationMs?: number;
|
|
51
|
-
}
|
|
52
|
-
export declare class PreviewManager {
|
|
53
|
-
private dataDir;
|
|
54
|
-
private dbPath;
|
|
55
|
-
constructor(options?: {
|
|
56
|
-
dataDir?: string;
|
|
57
|
-
});
|
|
58
|
-
private openDb;
|
|
59
|
-
ensureSchema(db?: Database): void;
|
|
60
|
-
private rowToSprite;
|
|
61
|
-
private rowToDeployment;
|
|
62
|
-
registerSprite(projectName: string, projectPath: string, spriteName: string, options?: RegisterSpriteOptions): SpriteRecord;
|
|
63
|
-
getSprite(projectName: string): SpriteRecord | null;
|
|
64
|
-
getSpriteById(id: number): SpriteRecord | null;
|
|
65
|
-
listSprites(): SpriteRecord[];
|
|
66
|
-
updateSprite(projectName: string, updates: Partial<Pick<RegisterSpriteOptions, "devCommand" | "dopplerProject" | "port">>): SpriteRecord | null;
|
|
67
|
-
deleteSprite(projectName: string): boolean;
|
|
68
|
-
recordDeployment(spriteId: number, status: DeploymentStatus, options?: RecordDeploymentOptions): DeploymentRecord;
|
|
69
|
-
updateDeployment(id: number, updates: UpdateDeploymentOptions): DeploymentRecord | null;
|
|
70
|
-
getDeployment(id: number): DeploymentRecord | null;
|
|
71
|
-
getLatestDeployment(spriteId: number): DeploymentRecord | null;
|
|
72
|
-
listDeployments(spriteId: number, limit?: number): DeploymentRecord[];
|
|
73
|
-
getActiveDeployments(): Array<DeploymentRecord & {
|
|
74
|
-
sprite: SpriteRecord;
|
|
75
|
-
}>;
|
|
76
|
-
}
|
|
77
|
-
//# sourceMappingURL=manager.d.ts.map
|