@linkshell/host 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 +11 -0
- package/dist/host/src/drivers/acp/connection.d.ts +61 -0
- package/dist/host/src/drivers/acp/connection.js +121 -0
- package/dist/host/src/drivers/acp/connection.js.map +1 -0
- package/dist/host/src/drivers/acp/driver.d.ts +110 -0
- package/dist/host/src/drivers/acp/driver.js +438 -0
- package/dist/host/src/drivers/acp/driver.js.map +1 -0
- package/dist/host/src/drivers/acp/mapper.d.ts +49 -0
- package/dist/host/src/drivers/acp/mapper.js +411 -0
- package/dist/host/src/drivers/acp/mapper.js.map +1 -0
- package/dist/host/src/drivers/auth.d.ts +7 -0
- package/dist/host/src/drivers/auth.js +57 -0
- package/dist/host/src/drivers/auth.js.map +1 -0
- package/dist/host/src/drivers/claude/driver.d.ts +76 -0
- package/dist/host/src/drivers/claude/driver.js +331 -0
- package/dist/host/src/drivers/claude/driver.js.map +1 -0
- package/dist/host/src/drivers/claude/transcript.d.ts +335 -0
- package/dist/host/src/drivers/claude/transcript.js +516 -0
- package/dist/host/src/drivers/claude/transcript.js.map +1 -0
- package/dist/host/src/drivers/codex/app-server.d.ts +36 -0
- package/dist/host/src/drivers/codex/app-server.js +144 -0
- package/dist/host/src/drivers/codex/app-server.js.map +1 -0
- package/dist/host/src/drivers/codex/driver.d.ts +89 -0
- package/dist/host/src/drivers/codex/driver.js +452 -0
- package/dist/host/src/drivers/codex/driver.js.map +1 -0
- package/dist/host/src/drivers/codex/mapper.d.ts +61 -0
- package/dist/host/src/drivers/codex/mapper.js +623 -0
- package/dist/host/src/drivers/codex/mapper.js.map +1 -0
- package/dist/host/src/drivers/codex/settings.d.ts +51 -0
- package/dist/host/src/drivers/codex/settings.js +107 -0
- package/dist/host/src/drivers/codex/settings.js.map +1 -0
- package/dist/host/src/drivers/images.d.ts +11 -0
- package/dist/host/src/drivers/images.js +34 -0
- package/dist/host/src/drivers/images.js.map +1 -0
- package/dist/host/src/drivers/nesting.d.ts +6 -0
- package/dist/host/src/drivers/nesting.js +25 -0
- package/dist/host/src/drivers/nesting.js.map +1 -0
- package/dist/host/src/drivers/registry.d.ts +21 -0
- package/dist/host/src/drivers/registry.js +30 -0
- package/dist/host/src/drivers/registry.js.map +1 -0
- package/dist/host/src/drivers/types.d.ts +105 -0
- package/dist/host/src/drivers/types.js +2 -0
- package/dist/host/src/drivers/types.js.map +1 -0
- package/dist/host/src/fs.d.ts +69 -0
- package/dist/host/src/fs.js +198 -0
- package/dist/host/src/fs.js.map +1 -0
- package/dist/host/src/gateway.d.ts +55 -0
- package/dist/host/src/gateway.js +263 -0
- package/dist/host/src/gateway.js.map +1 -0
- package/dist/host/src/host.d.ts +51 -0
- package/dist/host/src/host.js +133 -0
- package/dist/host/src/host.js.map +1 -0
- package/dist/host/src/hub.d.ts +89 -0
- package/dist/host/src/hub.js +592 -0
- package/dist/host/src/hub.js.map +1 -0
- package/dist/host/src/index.d.ts +10 -0
- package/dist/host/src/index.js +10 -0
- package/dist/host/src/index.js.map +1 -0
- package/dist/host/src/ports.d.ts +24 -0
- package/dist/host/src/ports.js +201 -0
- package/dist/host/src/ports.js.map +1 -0
- package/dist/host/src/rpc/client.d.ts +9 -0
- package/dist/host/src/rpc/client.js +42 -0
- package/dist/host/src/rpc/client.js.map +1 -0
- package/dist/host/src/rpc/server.d.ts +52 -0
- package/dist/host/src/rpc/server.js +293 -0
- package/dist/host/src/rpc/server.js.map +1 -0
- package/dist/host/src/screen.d.ts +30 -0
- package/dist/host/src/screen.js +230 -0
- package/dist/host/src/screen.js.map +1 -0
- package/dist/host/src/shell-env.d.ts +8 -0
- package/dist/host/src/shell-env.js +39 -0
- package/dist/host/src/shell-env.js.map +1 -0
- package/dist/host/src/store.d.ts +75 -0
- package/dist/host/src/store.js +265 -0
- package/dist/host/src/store.js.map +1 -0
- package/dist/host/src/terminals.d.ts +55 -0
- package/dist/host/src/terminals.js +367 -0
- package/dist/host/src/terminals.js.map +1 -0
- package/dist/host/tsconfig.tsbuildinfo +1 -0
- package/dist/wire/src/crypto.d.ts +65 -0
- package/dist/wire/src/crypto.js +253 -0
- package/dist/wire/src/crypto.js.map +1 -0
- package/dist/wire/src/index.d.ts +8 -0
- package/dist/wire/src/index.js +9 -0
- package/dist/wire/src/index.js.map +1 -0
- package/dist/wire/src/model.d.ts +704 -0
- package/dist/wire/src/model.js +163 -0
- package/dist/wire/src/model.js.map +1 -0
- package/dist/wire/src/peer.d.ts +42 -0
- package/dist/wire/src/peer.js +143 -0
- package/dist/wire/src/peer.js.map +1 -0
- package/dist/wire/src/relay-client.d.ts +82 -0
- package/dist/wire/src/relay-client.js +259 -0
- package/dist/wire/src/relay-client.js.map +1 -0
- package/dist/wire/src/relay.d.ts +481 -0
- package/dist/wire/src/relay.js +129 -0
- package/dist/wire/src/relay.js.map +1 -0
- package/dist/wire/src/rpc.d.ts +4170 -0
- package/dist/wire/src/rpc.js +332 -0
- package/dist/wire/src/rpc.js.map +1 -0
- package/dist/wire/src/shell.d.ts +2 -0
- package/dist/wire/src/shell.js +62 -0
- package/dist/wire/src/shell.js.map +1 -0
- package/dist/wire/src/updates.d.ts +3325 -0
- package/dist/wire/src/updates.js +210 -0
- package/dist/wire/src/updates.js.map +1 -0
- package/package.json +53 -0
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import { DatabaseSync } from "node:sqlite";
|
|
2
|
+
import { basename } from "node:path";
|
|
3
|
+
const SCHEMA = `
|
|
4
|
+
PRAGMA journal_mode = WAL;
|
|
5
|
+
PRAGMA synchronous = NORMAL;
|
|
6
|
+
CREATE TABLE IF NOT EXISTS sessions (
|
|
7
|
+
id TEXT PRIMARY KEY,
|
|
8
|
+
agent TEXT NOT NULL,
|
|
9
|
+
native_id TEXT NOT NULL,
|
|
10
|
+
title TEXT,
|
|
11
|
+
preview TEXT,
|
|
12
|
+
cwd TEXT NOT NULL,
|
|
13
|
+
state TEXT NOT NULL,
|
|
14
|
+
driver TEXT,
|
|
15
|
+
pending_permissions INTEGER NOT NULL DEFAULT 0,
|
|
16
|
+
model TEXT,
|
|
17
|
+
created_at INTEGER NOT NULL,
|
|
18
|
+
updated_at INTEGER NOT NULL,
|
|
19
|
+
last_seq INTEGER NOT NULL DEFAULT 0,
|
|
20
|
+
archived INTEGER NOT NULL DEFAULT 0
|
|
21
|
+
);
|
|
22
|
+
CREATE INDEX IF NOT EXISTS sessions_by_updated ON sessions (updated_at DESC);
|
|
23
|
+
CREATE TABLE IF NOT EXISTS events (
|
|
24
|
+
session_id TEXT NOT NULL,
|
|
25
|
+
seq INTEGER NOT NULL,
|
|
26
|
+
ts INTEGER NOT NULL,
|
|
27
|
+
body TEXT NOT NULL,
|
|
28
|
+
PRIMARY KEY (session_id, seq)
|
|
29
|
+
) WITHOUT ROWID;
|
|
30
|
+
CREATE TABLE IF NOT EXISTS logged_items (
|
|
31
|
+
session_id TEXT NOT NULL,
|
|
32
|
+
item_id TEXT NOT NULL,
|
|
33
|
+
PRIMARY KEY (session_id, item_id)
|
|
34
|
+
) WITHOUT ROWID;
|
|
35
|
+
CREATE TABLE IF NOT EXISTS driver_state (
|
|
36
|
+
session_id TEXT NOT NULL,
|
|
37
|
+
key TEXT NOT NULL,
|
|
38
|
+
value TEXT NOT NULL,
|
|
39
|
+
PRIMARY KEY (session_id, key)
|
|
40
|
+
) WITHOUT ROWID;
|
|
41
|
+
CREATE TABLE IF NOT EXISTS client_messages (
|
|
42
|
+
session_id TEXT NOT NULL,
|
|
43
|
+
client_message_id TEXT NOT NULL,
|
|
44
|
+
ts INTEGER NOT NULL,
|
|
45
|
+
PRIMARY KEY (session_id, client_message_id)
|
|
46
|
+
) WITHOUT ROWID;
|
|
47
|
+
CREATE TABLE IF NOT EXISTS terminals (
|
|
48
|
+
id TEXT PRIMARY KEY,
|
|
49
|
+
cwd TEXT NOT NULL,
|
|
50
|
+
title TEXT NOT NULL,
|
|
51
|
+
command TEXT,
|
|
52
|
+
cols INTEGER NOT NULL,
|
|
53
|
+
rows INTEGER NOT NULL,
|
|
54
|
+
created_at INTEGER NOT NULL,
|
|
55
|
+
active_at INTEGER NOT NULL,
|
|
56
|
+
exit_code INTEGER,
|
|
57
|
+
ended INTEGER NOT NULL DEFAULT 0,
|
|
58
|
+
buffer TEXT NOT NULL DEFAULT ''
|
|
59
|
+
);
|
|
60
|
+
`;
|
|
61
|
+
const PATCH_COLUMNS = {
|
|
62
|
+
title: "title",
|
|
63
|
+
preview: "preview",
|
|
64
|
+
cwd: "cwd",
|
|
65
|
+
state: "state",
|
|
66
|
+
driver: "driver",
|
|
67
|
+
pendingPermissions: "pending_permissions",
|
|
68
|
+
model: "model",
|
|
69
|
+
updatedAt: "updated_at",
|
|
70
|
+
archived: "archived",
|
|
71
|
+
};
|
|
72
|
+
function toSummary(row) {
|
|
73
|
+
return {
|
|
74
|
+
id: row.id,
|
|
75
|
+
agent: row.agent,
|
|
76
|
+
nativeId: row.native_id,
|
|
77
|
+
title: row.title ?? undefined,
|
|
78
|
+
preview: row.preview ?? undefined,
|
|
79
|
+
cwd: row.cwd,
|
|
80
|
+
state: row.state,
|
|
81
|
+
driver: (row.driver ?? undefined),
|
|
82
|
+
pendingPermissions: row.pending_permissions,
|
|
83
|
+
model: row.model ?? undefined,
|
|
84
|
+
createdAt: row.created_at,
|
|
85
|
+
updatedAt: row.updated_at,
|
|
86
|
+
lastSeq: row.last_seq,
|
|
87
|
+
archived: row.archived === 1,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Durable host state: session summaries plus one append-only event log per
|
|
92
|
+
* session. Every update a client sees gets a per-session `seq`, so a client
|
|
93
|
+
* that reconnects asks for "everything after seq N" and gets exactly that.
|
|
94
|
+
*/
|
|
95
|
+
export class HostStore {
|
|
96
|
+
db;
|
|
97
|
+
constructor(path) {
|
|
98
|
+
this.db = new DatabaseSync(path);
|
|
99
|
+
this.db.exec(SCHEMA);
|
|
100
|
+
}
|
|
101
|
+
close() {
|
|
102
|
+
this.db.close();
|
|
103
|
+
}
|
|
104
|
+
// ── terminals ─────────────────────────────────────────────────────
|
|
105
|
+
saveTerminal(t) {
|
|
106
|
+
this.db
|
|
107
|
+
.prepare(`INSERT INTO terminals (id, cwd, title, command, cols, rows, created_at, active_at, exit_code, ended, buffer)
|
|
108
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
109
|
+
ON CONFLICT(id) DO UPDATE SET title = excluded.title, cols = excluded.cols, rows = excluded.rows,
|
|
110
|
+
active_at = excluded.active_at, exit_code = excluded.exit_code, ended = excluded.ended, buffer = excluded.buffer`)
|
|
111
|
+
.run(t.id, t.cwd, t.title, t.command ?? null, t.cols, t.rows, t.createdAt, t.activeAt, t.exitCode, t.ended ? 1 : 0, t.buffer);
|
|
112
|
+
}
|
|
113
|
+
listTerminals() {
|
|
114
|
+
const rows = this.db.prepare("SELECT * FROM terminals ORDER BY active_at DESC").all();
|
|
115
|
+
return rows.map((row) => ({
|
|
116
|
+
id: String(row.id),
|
|
117
|
+
cwd: String(row.cwd),
|
|
118
|
+
title: String(row.title),
|
|
119
|
+
command: row.command ? String(row.command) : undefined,
|
|
120
|
+
cols: Number(row.cols),
|
|
121
|
+
rows: Number(row.rows),
|
|
122
|
+
createdAt: Number(row.created_at),
|
|
123
|
+
activeAt: Number(row.active_at),
|
|
124
|
+
exitCode: row.exit_code === null ? null : Number(row.exit_code),
|
|
125
|
+
ended: Number(row.ended) === 1,
|
|
126
|
+
buffer: String(row.buffer),
|
|
127
|
+
}));
|
|
128
|
+
}
|
|
129
|
+
deleteTerminal(id) {
|
|
130
|
+
this.db.prepare("DELETE FROM terminals WHERE id = ?").run(id);
|
|
131
|
+
}
|
|
132
|
+
/** Inserts a session, or refreshes discovery fields of an existing one. */
|
|
133
|
+
upsertSession(input) {
|
|
134
|
+
const existing = this.getSession(input.id);
|
|
135
|
+
if (!existing) {
|
|
136
|
+
this.db
|
|
137
|
+
.prepare(`INSERT INTO sessions (id, agent, native_id, title, preview, cwd, state, model, created_at, updated_at)
|
|
138
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
139
|
+
.run(input.id, input.agent, input.nativeId, input.title ?? null, input.preview ?? null, input.cwd, input.state ?? "idle", input.model ?? null, input.createdAt, input.updatedAt);
|
|
140
|
+
return { summary: this.getSession(input.id), created: true };
|
|
141
|
+
}
|
|
142
|
+
const patch = {};
|
|
143
|
+
if (input.title && input.title !== existing.title)
|
|
144
|
+
patch.title = input.title;
|
|
145
|
+
if (input.preview && !existing.preview)
|
|
146
|
+
patch.preview = input.preview;
|
|
147
|
+
if (input.cwd && input.cwd !== existing.cwd)
|
|
148
|
+
patch.cwd = input.cwd;
|
|
149
|
+
if (input.model && input.model !== existing.model)
|
|
150
|
+
patch.model = input.model;
|
|
151
|
+
if (input.state && input.state !== existing.state)
|
|
152
|
+
patch.state = input.state;
|
|
153
|
+
if (input.updatedAt > existing.updatedAt)
|
|
154
|
+
patch.updatedAt = input.updatedAt;
|
|
155
|
+
const summary = Object.keys(patch).length > 0 ? this.patchSession(input.id, patch) : existing;
|
|
156
|
+
return { summary, created: false };
|
|
157
|
+
}
|
|
158
|
+
patchSession(id, patch) {
|
|
159
|
+
const sets = [];
|
|
160
|
+
const values = [];
|
|
161
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
162
|
+
if (value === undefined)
|
|
163
|
+
continue;
|
|
164
|
+
sets.push(`${PATCH_COLUMNS[key]} = ?`);
|
|
165
|
+
values.push(typeof value === "boolean" ? (value ? 1 : 0) : value);
|
|
166
|
+
}
|
|
167
|
+
if (sets.length > 0) {
|
|
168
|
+
this.db.prepare(`UPDATE sessions SET ${sets.join(", ")} WHERE id = ?`).run(...values, id);
|
|
169
|
+
}
|
|
170
|
+
const summary = this.getSession(id);
|
|
171
|
+
if (!summary)
|
|
172
|
+
throw new Error(`unknown session ${id}`);
|
|
173
|
+
return summary;
|
|
174
|
+
}
|
|
175
|
+
getSession(id) {
|
|
176
|
+
const row = this.db.prepare("SELECT * FROM sessions WHERE id = ?").get(id);
|
|
177
|
+
return row ? toSummary(row) : undefined;
|
|
178
|
+
}
|
|
179
|
+
listSessions(options = {}) {
|
|
180
|
+
const where = [];
|
|
181
|
+
const values = [];
|
|
182
|
+
if (!options.includeArchived)
|
|
183
|
+
where.push("archived = 0");
|
|
184
|
+
if (options.before !== undefined) {
|
|
185
|
+
where.push("updated_at < ?");
|
|
186
|
+
values.push(options.before);
|
|
187
|
+
}
|
|
188
|
+
const sql = `SELECT * FROM sessions ${where.length ? `WHERE ${where.join(" AND ")}` : ""}
|
|
189
|
+
ORDER BY updated_at DESC LIMIT ?`;
|
|
190
|
+
const rows = this.db.prepare(sql).all(...values, options.limit ?? 50);
|
|
191
|
+
return rows.map(toSummary);
|
|
192
|
+
}
|
|
193
|
+
listProjects(limit = 50) {
|
|
194
|
+
const rows = this.db
|
|
195
|
+
.prepare(`SELECT cwd, MAX(updated_at) AS last_active_at, COUNT(*) AS session_count
|
|
196
|
+
FROM sessions WHERE archived = 0 GROUP BY cwd ORDER BY last_active_at DESC LIMIT ?`)
|
|
197
|
+
.all(limit);
|
|
198
|
+
return rows.map((row) => ({
|
|
199
|
+
cwd: row.cwd,
|
|
200
|
+
name: basename(row.cwd) || row.cwd,
|
|
201
|
+
lastActiveAt: row.last_active_at,
|
|
202
|
+
sessionCount: row.session_count,
|
|
203
|
+
}));
|
|
204
|
+
}
|
|
205
|
+
/** Appends one update to the session's log and returns it with its seq. */
|
|
206
|
+
appendEvent(sessionId, update, ts = Date.now()) {
|
|
207
|
+
this.db.exec("BEGIN IMMEDIATE");
|
|
208
|
+
try {
|
|
209
|
+
const row = this.db.prepare("SELECT last_seq FROM sessions WHERE id = ?").get(sessionId);
|
|
210
|
+
if (!row)
|
|
211
|
+
throw new Error(`unknown session ${sessionId}`);
|
|
212
|
+
const seq = row.last_seq + 1;
|
|
213
|
+
this.db
|
|
214
|
+
.prepare("INSERT INTO events (session_id, seq, ts, body) VALUES (?, ?, ?, ?)")
|
|
215
|
+
.run(sessionId, seq, ts, JSON.stringify(update));
|
|
216
|
+
this.db.prepare("UPDATE sessions SET last_seq = ?, updated_at = MAX(updated_at, ?) WHERE id = ?").run(seq, ts, sessionId);
|
|
217
|
+
this.db.exec("COMMIT");
|
|
218
|
+
return { sessionId, seq, ts, update };
|
|
219
|
+
}
|
|
220
|
+
catch (error) {
|
|
221
|
+
this.db.exec("ROLLBACK");
|
|
222
|
+
throw error;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
readEvents(sessionId, afterSeq, limit = 5000) {
|
|
226
|
+
const rows = this.db
|
|
227
|
+
.prepare("SELECT seq, ts, body FROM events WHERE session_id = ? AND seq > ? ORDER BY seq ASC LIMIT ?")
|
|
228
|
+
.all(sessionId, afterSeq, limit);
|
|
229
|
+
return rows.map((row) => ({ sessionId, seq: row.seq, ts: row.ts, update: JSON.parse(row.body) }));
|
|
230
|
+
}
|
|
231
|
+
/** Marks a native item (message, tool call) as present in the log. Returns false if it already was. */
|
|
232
|
+
markItemLogged(sessionId, itemId) {
|
|
233
|
+
const result = this.db
|
|
234
|
+
.prepare("INSERT OR IGNORE INTO logged_items (session_id, item_id) VALUES (?, ?)")
|
|
235
|
+
.run(sessionId, itemId);
|
|
236
|
+
return Number(result.changes) > 0;
|
|
237
|
+
}
|
|
238
|
+
isItemLogged(sessionId, itemId) {
|
|
239
|
+
return (this.db.prepare("SELECT 1 FROM logged_items WHERE session_id = ? AND item_id = ?").get(sessionId, itemId) !==
|
|
240
|
+
undefined);
|
|
241
|
+
}
|
|
242
|
+
/** Records a client message id. Returns false when it was already delivered. */
|
|
243
|
+
claimClientMessage(sessionId, clientMessageId, ts = Date.now()) {
|
|
244
|
+
const result = this.db
|
|
245
|
+
.prepare("INSERT OR IGNORE INTO client_messages (session_id, client_message_id, ts) VALUES (?, ?, ?)")
|
|
246
|
+
.run(sessionId, clientMessageId, ts);
|
|
247
|
+
return Number(result.changes) > 0;
|
|
248
|
+
}
|
|
249
|
+
/** Small per-session values a driver keeps across restarts (e.g. a transcript read offset). */
|
|
250
|
+
getDriverState(sessionId, key) {
|
|
251
|
+
const row = this.db.prepare("SELECT value FROM driver_state WHERE session_id = ? AND key = ?").get(sessionId, key);
|
|
252
|
+
return row?.value;
|
|
253
|
+
}
|
|
254
|
+
setDriverState(sessionId, key, value) {
|
|
255
|
+
this.db
|
|
256
|
+
.prepare("INSERT INTO driver_state (session_id, key, value) VALUES (?, ?, ?) ON CONFLICT (session_id, key) DO UPDATE SET value = excluded.value")
|
|
257
|
+
.run(sessionId, key, value);
|
|
258
|
+
}
|
|
259
|
+
releaseClientMessage(sessionId, clientMessageId) {
|
|
260
|
+
this.db
|
|
261
|
+
.prepare("DELETE FROM client_messages WHERE session_id = ? AND client_message_id = ?")
|
|
262
|
+
.run(sessionId, clientMessageId);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { type TerminalInfo } from "@linkshell/wire";
|
|
2
|
+
import type { HostStore } from "./store.js";
|
|
3
|
+
export type OutputListener = (seq: number, data: string) => void;
|
|
4
|
+
export type TerminalChangeListener = (terminal: TerminalInfo, closed?: boolean) => void;
|
|
5
|
+
/**
|
|
6
|
+
* Live shells plus the history of ended ones. Everything is saved, so after
|
|
7
|
+
* a shell exits (or the host restarts) its output can still be read, and it
|
|
8
|
+
* can be run again.
|
|
9
|
+
*/
|
|
10
|
+
export declare class TerminalManager {
|
|
11
|
+
private readonly env?;
|
|
12
|
+
private readonly store?;
|
|
13
|
+
private readonly terminals;
|
|
14
|
+
/** Ended terminals, as saved. */
|
|
15
|
+
private readonly history;
|
|
16
|
+
private readonly timer;
|
|
17
|
+
private readonly changeListeners;
|
|
18
|
+
private stopped;
|
|
19
|
+
/** @param env The user's login-shell environment. */
|
|
20
|
+
constructor(env?: NodeJS.ProcessEnv | undefined, store?: HostStore | undefined);
|
|
21
|
+
onChange(listener: TerminalChangeListener): () => void;
|
|
22
|
+
private emit;
|
|
23
|
+
private save;
|
|
24
|
+
list(): TerminalInfo[];
|
|
25
|
+
create(options: {
|
|
26
|
+
cwd?: string;
|
|
27
|
+
command?: string;
|
|
28
|
+
cols: number;
|
|
29
|
+
rows: number;
|
|
30
|
+
}): TerminalInfo;
|
|
31
|
+
attach(id: string, listener: OutputListener, fromSeq?: number): {
|
|
32
|
+
replay: string;
|
|
33
|
+
reset: boolean;
|
|
34
|
+
seq: number;
|
|
35
|
+
terminal: {
|
|
36
|
+
id: string;
|
|
37
|
+
title: string;
|
|
38
|
+
cwd: string;
|
|
39
|
+
createdAt: number;
|
|
40
|
+
cols: number;
|
|
41
|
+
rows: number;
|
|
42
|
+
activeAt: number;
|
|
43
|
+
command?: string | undefined;
|
|
44
|
+
exitCode?: number | null | undefined;
|
|
45
|
+
interrupted?: boolean | undefined;
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
detach(id: string, listener: OutputListener): void;
|
|
49
|
+
input(id: string, data: string): void;
|
|
50
|
+
resize(id: string, cols: number, rows: number): void;
|
|
51
|
+
/** Ends a live terminal and forgets it, or deletes an ended one from history. */
|
|
52
|
+
close(id: string): void;
|
|
53
|
+
stop(): void;
|
|
54
|
+
private live;
|
|
55
|
+
}
|