@monotykamary/localterm-server 2.76.6 → 2.76.8
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/dist/cdp/cdp-client.d.ts +0 -10
- package/dist/cdp/cdp-client.d.ts.map +1 -1
- package/dist/cdp/cdp-client.js +0 -42
- package/dist/cdp/cdp-client.js.map +1 -1
- package/dist/constants.d.ts +0 -4
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +0 -15
- package/dist/constants.js.map +1 -1
- package/dist/daemon-config-store.d.ts +0 -2
- package/dist/daemon-config-store.d.ts.map +1 -1
- package/dist/daemon-config-store.js +0 -15
- package/dist/daemon-config-store.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -132
- package/dist/index.js.map +1 -1
- package/dist/schemas.d.ts +0 -14
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +3 -20
- package/dist/schemas.js.map +1 -1
- package/dist/session-client-hub.d.ts +0 -7
- package/dist/session-client-hub.d.ts.map +1 -1
- package/dist/session-client-hub.js +0 -60
- package/dist/session-client-hub.js.map +1 -1
- package/dist/session-manager.d.ts +0 -7
- package/dist/session-manager.d.ts.map +1 -1
- package/dist/session-manager.js +0 -9
- package/dist/session-manager.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -22,7 +22,7 @@ import { detectWithExplicitPort } from "./cdp/discover-explicit-endpoint.js";
|
|
|
22
22
|
import { DaemonConfigStore } from "./daemon-config-store.js";
|
|
23
23
|
import { formatCandidates, resolveCandidates, resolveCompletionContext, } from "./completion/index.js";
|
|
24
24
|
import { z } from "zod";
|
|
25
|
-
import { ACTIVITY_DIRNAME, ACTIVITY_REFRESH_DEBOUNCE_MS, ACTIVITY_WATCHED_PROGRAMS, AUTOMATION_EVENT_DEBOUNCE_MS, AUTOMATION_RECONCILE_MIN_DOWNTIME_MS, AUTOMATION_RUN_QUERY_PARAM, AUTOMATION_WATCH_DEBOUNCE_MS, AUTOMATION_WATCH_POST_RUN_GRACE_MS, AUTOMATION_WEBHOOK_DEBOUNCE_MS, DEFAULT_HOST, DEFAULT_PORT, FRIENDLY_HOSTNAME, GIT_DIRTY_THROTTLE_MS, GIT_MAX_REF_LENGTH, HERDR_THEME_SYNC_DEBOUNCE_MS, HIBERNATE_FILENAME, HTTP_STATUS_ACCEPTED, HTTP_STATUS_BAD_REQUEST, HTTP_STATUS_CONFLICT, HTTP_STATUS_CREATED, HTTP_STATUS_NOT_FOUND, HTTP_STATUS_PAYLOAD_TOO_LARGE, HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE, MAX_AUTOMATIONS, MAX_IMAGE_UPLOAD_BYTES, MAX_IMAGE_UPLOAD_REQUEST_BYTES, MAX_PROCESSES, MAX_SECRETS, MS_PER_MINUTE, PROCESSES_FILENAME, SECRETS_FILENAME, THEMES_FILENAME, FONTS_FILENAME, SECRETS_SHIMS_DIRNAME, SECRET_EXPORT_SCRYPT_WORK_FACTOR, AUTOMATION_AGENT_SESSIONS_DIRNAME, SERVER_STOP_GRACE_MS, SESSION_ID_QUERY_PARAM,
|
|
25
|
+
import { ACTIVITY_DIRNAME, ACTIVITY_REFRESH_DEBOUNCE_MS, ACTIVITY_WATCHED_PROGRAMS, AUTOMATION_EVENT_DEBOUNCE_MS, AUTOMATION_RECONCILE_MIN_DOWNTIME_MS, AUTOMATION_RUN_QUERY_PARAM, AUTOMATION_WATCH_DEBOUNCE_MS, AUTOMATION_WATCH_POST_RUN_GRACE_MS, AUTOMATION_WEBHOOK_DEBOUNCE_MS, DEFAULT_HOST, DEFAULT_PORT, FRIENDLY_HOSTNAME, GIT_DIRTY_THROTTLE_MS, GIT_MAX_REF_LENGTH, HERDR_THEME_SYNC_DEBOUNCE_MS, HIBERNATE_FILENAME, HTTP_STATUS_ACCEPTED, HTTP_STATUS_BAD_REQUEST, HTTP_STATUS_CONFLICT, HTTP_STATUS_CREATED, HTTP_STATUS_NOT_FOUND, HTTP_STATUS_PAYLOAD_TOO_LARGE, HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE, MAX_AUTOMATIONS, MAX_IMAGE_UPLOAD_BYTES, MAX_IMAGE_UPLOAD_REQUEST_BYTES, MAX_PROCESSES, MAX_SECRETS, MS_PER_MINUTE, PROCESSES_FILENAME, SECRETS_FILENAME, THEMES_FILENAME, FONTS_FILENAME, SECRETS_SHIMS_DIRNAME, SECRET_EXPORT_SCRYPT_WORK_FACTOR, AUTOMATION_AGENT_SESSIONS_DIRNAME, SERVER_STOP_GRACE_MS, SESSION_ID_QUERY_PARAM, SESSION_ACTIVITY_WINDOW_MS, WINDOW_ID_QUERY_PARAM, WAIT_DEFAULT_TIMEOUT_MS, WS_BACKPRESSURE_THRESHOLD_BYTES, WS_CLOSE_BACKPRESSURE, WS_CLOSE_CAPACITY_REACHED, WS_CLOSE_POLICY_VIOLATION, WS_HEARTBEAT_GRACE_MS, WS_HEARTBEAT_INTERVAL_MS, WS_HEARTBEAT_TIMEOUT_MS, WS_MAX_INBOUND_PAYLOAD_BYTES, WS_READY_STATE_OPEN, AUTH_SECRET_FILENAME, AUTH_COOKIE_NAME, UPDATE_CHECK_FILENAME, } from "./constants.js";
|
|
26
26
|
import { getDefaultShell, listKnownShells, resolveShellOverride } from "./default-shell.js";
|
|
27
27
|
import { resolveWindowId } from "./utils/resolve-window-id.js";
|
|
28
28
|
import { resolveTermBackspaceSequence } from "./utils/resolve-term-backspace-sequence.js";
|
|
@@ -40,7 +40,6 @@ import { WebhookTriggerManager } from "./webhook-trigger-manager.js";
|
|
|
40
40
|
import { getGitBranchInfo, getGitBranchPr, getGitDiff, getGitDiffFileContents, getGitDiffFilePatch, getGitDiffFiles, getGitDiffSummary, } from "./git-diff.js";
|
|
41
41
|
import { HeartbeatStore } from "./heartbeat-store.js";
|
|
42
42
|
import { HibernateStore } from "./hibernate-store.js";
|
|
43
|
-
import { WorkspaceStore } from "./workspace-store.js";
|
|
44
43
|
import { createDefaultSecretBackend } from "./secret-backend.js";
|
|
45
44
|
import { SecretStore } from "./secret-store.js";
|
|
46
45
|
import { ProcessStore } from "./process-store.js";
|
|
@@ -194,7 +193,7 @@ const normalizeMouseAction = (input) => {
|
|
|
194
193
|
};
|
|
195
194
|
const buildApiRoutes = (ctx) => {
|
|
196
195
|
const api = new Hono();
|
|
197
|
-
const { registry, ownerFor, cdpClient, secretBackend, secretExportScryptWorkFactor, secretStore, shimsDir, processStore, themeStore, fontStore, syncSecretShims, automationStore, broadcastAutomations, syncFolderWatchers, syncSessionEventListeners, webhookTriggerManager, worktreeConfigStore, portsSnapshotProcesses, portsSnapshotListeners, toAutomationWithNextRun, listAutomationsWithNextRun, tryLaunch, getCdpPort, applyCdpPort, getGraceSeconds, applyGraceSeconds,
|
|
196
|
+
const { registry, ownerFor, cdpClient, secretBackend, secretExportScryptWorkFactor, secretStore, shimsDir, processStore, themeStore, fontStore, syncSecretShims, automationStore, broadcastAutomations, syncFolderWatchers, syncSessionEventListeners, webhookTriggerManager, worktreeConfigStore, portsSnapshotProcesses, portsSnapshotListeners, toAutomationWithNextRun, listAutomationsWithNextRun, tryLaunch, getCdpPort, applyCdpPort, getGraceSeconds, applyGraceSeconds, connectCdpNow, buildTabUrl, mintViewerCookie, stateDirectory, broadcastThemes, broadcastFonts, updateCheckStore, } = ctx;
|
|
198
197
|
// Headless SGR-1006 fallback for `mouse` when no CDP tab is reachable:
|
|
199
198
|
// encode the gesture as SGR bytes and write them straight to the PTY. Closes
|
|
200
199
|
// over `registry` so the automation layer stays CDP-agnostic. Coords arrive
|
|
@@ -1584,7 +1583,6 @@ const buildApiRoutes = (ctx) => {
|
|
|
1584
1583
|
api.get("/config", (context) => context.json({
|
|
1585
1584
|
cdpPort: getCdpPort(),
|
|
1586
1585
|
graceSeconds: getGraceSeconds(),
|
|
1587
|
-
workspaceRestore: getWorkspaceRestore(),
|
|
1588
1586
|
defaultShell: getDefaultShell(),
|
|
1589
1587
|
shells: listKnownShells(),
|
|
1590
1588
|
}));
|
|
@@ -1597,9 +1595,6 @@ const buildApiRoutes = (ctx) => {
|
|
|
1597
1595
|
graceSeconds: parsed.data.graceSeconds === undefined
|
|
1598
1596
|
? getGraceSeconds()
|
|
1599
1597
|
: applyGraceSeconds(parsed.data.graceSeconds),
|
|
1600
|
-
workspaceRestore: parsed.data.workspaceRestore === undefined
|
|
1601
|
-
? getWorkspaceRestore()
|
|
1602
|
-
: applyWorkspaceRestore(parsed.data.workspaceRestore),
|
|
1603
1598
|
defaultShell: getDefaultShell(),
|
|
1604
1599
|
shells: listKnownShells(),
|
|
1605
1600
|
});
|
|
@@ -1677,15 +1672,10 @@ export const createServer = async (options = {}) => {
|
|
|
1677
1672
|
onOutputActivity: () => caffeinateManager.noteOutputActivity(),
|
|
1678
1673
|
onSessionActivity: () => {
|
|
1679
1674
|
caffeinateManager.pokeAuto();
|
|
1680
|
-
scheduleWorkspaceSnapshot();
|
|
1681
1675
|
refreshHerdrThemeSyncState();
|
|
1682
1676
|
},
|
|
1683
1677
|
onSessionEvent: (event, cwd) => {
|
|
1684
1678
|
sessionEventManager.onSessionEvent(event, cwd);
|
|
1685
|
-
// A cwd change reshapes the workspace manifest (the tab's respawn cwd
|
|
1686
|
-
// moves), so re-snapshot alongside the attach/detach-driven snapshot.
|
|
1687
|
-
if (event === "cwd")
|
|
1688
|
-
scheduleWorkspaceSnapshot();
|
|
1689
1679
|
},
|
|
1690
1680
|
onAutomationExit: (automationId, runId, exitCode, log) => {
|
|
1691
1681
|
automationStore.updateRun(automationId, runId, {
|
|
@@ -1770,10 +1760,9 @@ export const createServer = async (options = {}) => {
|
|
|
1770
1760
|
const caffeinateController = options.caffeinateController ?? new CaffeinateController();
|
|
1771
1761
|
const caffeinatePreferencesStore = new CaffeinatePreferencesStore(path.join(stateDirectory, "caffeinate.json"));
|
|
1772
1762
|
const worktreeConfigStore = new WorktreeConfigStore(stateDirectory);
|
|
1773
|
-
const workspaceStore = new WorkspaceStore(path.join(stateDirectory, WORKSPACE_FILENAME));
|
|
1774
1763
|
const hibernateStore = new HibernateStore(path.join(stateDirectory, HIBERNATE_FILENAME));
|
|
1775
1764
|
// Immutable shutdown snapshot for this daemon lifetime. Exact old session ids
|
|
1776
|
-
// let surviving
|
|
1765
|
+
// let surviving browser tabs recover only their own text.
|
|
1777
1766
|
const startupHibernateEntries = hibernateStore.read();
|
|
1778
1767
|
// Per-process secret injection: a backend (macOS Keychain on darwin) holds
|
|
1779
1768
|
// secret values; a secret is an identity + the env var it exports
|
|
@@ -2302,11 +2291,6 @@ export const createServer = async (options = {}) => {
|
|
|
2302
2291
|
registry.rearmGrace();
|
|
2303
2292
|
return next;
|
|
2304
2293
|
};
|
|
2305
|
-
// Persist + read the workspace-restore toggle. Read at restore time, so a
|
|
2306
|
-
// `PUT /api/config` change takes effect on the next start (the restore runs
|
|
2307
|
-
// once at startup, not live-reactively).
|
|
2308
|
-
const getWorkspaceRestore = () => daemonConfigStore.getWorkspaceRestore();
|
|
2309
|
-
const applyWorkspaceRestore = (enabled) => daemonConfigStore.setWorkspaceRestore(enabled);
|
|
2310
2294
|
// Explicit "Connect now" (Settings → Automation browser → Connect): drop any
|
|
2311
2295
|
// live socket and await a fresh connect so the caller learns the outcome —
|
|
2312
2296
|
// connected + which browser, or the error that explains a failure (e.g. a
|
|
@@ -2331,45 +2315,6 @@ export const createServer = async (options = {}) => {
|
|
|
2331
2315
|
};
|
|
2332
2316
|
}
|
|
2333
2317
|
};
|
|
2334
|
-
// Workspace restore: reopen the user's last tabs via CDP on start (a
|
|
2335
|
-
// tmux-resurrect/herdr-style restore of the *layout*; the shells themselves
|
|
2336
|
-
// don't survive a stop). The manifest is snapshotted to disk — debounced on
|
|
2337
|
-
// attach/detach churn (scheduleWorkspaceSnapshot, hooked into onSessionActivity)
|
|
2338
|
-
// and flushed on graceful stop — so a restart, graceful or a crash, can reopen
|
|
2339
|
-
// the same tabs. Triggered once per (owner, windowId) after the first desktop
|
|
2340
|
-
// tab pairs with CDP, on a quiet window so surviving tabs (a daemon restart
|
|
2341
|
-
// with the browser left open) reattach and are counted before the deficit is
|
|
2342
|
-
// opened. Excludes automation-run tabs and dormant shells (filtered in
|
|
2343
|
-
// SessionManager.workspaceEntries), so only tabs that were actively open
|
|
2344
|
-
// come back. Opt out via Settings → Sessions (config.json workspaceRestore).
|
|
2345
|
-
let workspaceSnapshotTimer = null;
|
|
2346
|
-
const scheduleWorkspaceSnapshot = () => {
|
|
2347
|
-
if (workspaceSnapshotTimer !== null)
|
|
2348
|
-
clearTimeout(workspaceSnapshotTimer);
|
|
2349
|
-
const timer = setTimeout(() => {
|
|
2350
|
-
workspaceSnapshotTimer = null;
|
|
2351
|
-
workspaceStore.write(registry.workspaceEntries());
|
|
2352
|
-
}, WORKSPACE_SNAPSHOT_DEBOUNCE_MS);
|
|
2353
|
-
timer.unref?.();
|
|
2354
|
-
workspaceSnapshotTimer = timer;
|
|
2355
|
-
};
|
|
2356
|
-
const flushWorkspaceSnapshot = () => {
|
|
2357
|
-
if (workspaceSnapshotTimer !== null) {
|
|
2358
|
-
clearTimeout(workspaceSnapshotTimer);
|
|
2359
|
-
workspaceSnapshotTimer = null;
|
|
2360
|
-
}
|
|
2361
|
-
workspaceStore.write(registry.workspaceEntries());
|
|
2362
|
-
};
|
|
2363
|
-
const buildSpawnTabUrl = (cwd, shell, sessionId) => {
|
|
2364
|
-
const url = new URL(localOrigin ?? publicOrigin ?? `http://${FRIENDLY_HOSTNAME}:${actualPort}`);
|
|
2365
|
-
if (cwd)
|
|
2366
|
-
url.searchParams.set("cwd", cwd);
|
|
2367
|
-
if (shell)
|
|
2368
|
-
url.searchParams.set("shell", shell);
|
|
2369
|
-
if (sessionId)
|
|
2370
|
-
url.searchParams.set(SESSION_ID_QUERY_PARAM, sessionId);
|
|
2371
|
-
return url.toString();
|
|
2372
|
-
};
|
|
2373
2318
|
const hibernatedTabFor = (owner, windowId, sessionId) => {
|
|
2374
2319
|
if (!windowId || !sessionId)
|
|
2375
2320
|
return undefined;
|
|
@@ -2377,70 +2322,6 @@ export const createServer = async (options = {}) => {
|
|
|
2377
2322
|
.find((entry) => entry.owner === owner && entry.windowId === windowId)
|
|
2378
2323
|
?.tabs.find((tab) => tab.sessionId === sessionId);
|
|
2379
2324
|
};
|
|
2380
|
-
const restoredWorkspaceKeys = new Set();
|
|
2381
|
-
const workspaceRestoreTimers = new Map();
|
|
2382
|
-
const scheduleWorkspaceRestore = (owner, windowId) => {
|
|
2383
|
-
if (!windowId)
|
|
2384
|
-
return;
|
|
2385
|
-
const key = `${owner ?? ""}\u0000${windowId}`;
|
|
2386
|
-
if (restoredWorkspaceKeys.has(key))
|
|
2387
|
-
return;
|
|
2388
|
-
const existing = workspaceRestoreTimers.get(key);
|
|
2389
|
-
if (existing)
|
|
2390
|
-
clearTimeout(existing);
|
|
2391
|
-
const timer = setTimeout(() => {
|
|
2392
|
-
workspaceRestoreTimers.delete(key);
|
|
2393
|
-
if (restoredWorkspaceKeys.has(key))
|
|
2394
|
-
return;
|
|
2395
|
-
restoredWorkspaceKeys.add(key);
|
|
2396
|
-
void restoreWorkspace(owner, windowId);
|
|
2397
|
-
}, WORKSPACE_RESTORE_SETTLE_MS);
|
|
2398
|
-
timer.unref?.();
|
|
2399
|
-
workspaceRestoreTimers.set(key, timer);
|
|
2400
|
-
};
|
|
2401
|
-
const restoreWorkspace = async (owner, windowId) => {
|
|
2402
|
-
if (!daemonConfigStore.getWorkspaceRestore())
|
|
2403
|
-
return;
|
|
2404
|
-
if (!cdpClient || !cdpClient.isConnected())
|
|
2405
|
-
return;
|
|
2406
|
-
const hibernatedEntry = startupHibernateEntries.find((candidate) => candidate.owner === owner && candidate.windowId === windowId);
|
|
2407
|
-
const workspaceEntry = workspaceStore
|
|
2408
|
-
.read()
|
|
2409
|
-
.find((candidate) => candidate.owner === owner && candidate.windowId === windowId);
|
|
2410
|
-
const manifest = hibernatedEntry?.tabs ?? workspaceEntry?.tabs ?? [];
|
|
2411
|
-
if (manifest.length === 0)
|
|
2412
|
-
return;
|
|
2413
|
-
const urlFor = (index) => {
|
|
2414
|
-
const tab = manifest[index];
|
|
2415
|
-
const sessionId = "sessionId" in tab && typeof tab.sessionId === "string" ? tab.sessionId : undefined;
|
|
2416
|
-
return buildSpawnTabUrl(tab.cwd, tab.shell, sessionId);
|
|
2417
|
-
};
|
|
2418
|
-
const openCount = registry.attachedClientCount(owner, windowId);
|
|
2419
|
-
if (openCount >= manifest.length)
|
|
2420
|
-
return;
|
|
2421
|
-
if (openCount === 0) {
|
|
2422
|
-
for (let index = 0; index < manifest.length; index += 1) {
|
|
2423
|
-
await cdpClient.openBackgroundTab(urlFor(index));
|
|
2424
|
-
}
|
|
2425
|
-
return;
|
|
2426
|
-
}
|
|
2427
|
-
if (openCount === 1) {
|
|
2428
|
-
// Browser was fully closed; repoint the lone bootstrap to the first tab.
|
|
2429
|
-
const firstTargetId = [...wsToTargetId.entries()].find(([ws]) => {
|
|
2430
|
-
const profile = registry.clientProfile(ws);
|
|
2431
|
-
return profile !== null && profile.owner === owner && profile.windowId === windowId;
|
|
2432
|
-
})?.[1];
|
|
2433
|
-
if (firstTargetId)
|
|
2434
|
-
await cdpClient.navigateTab(firstTargetId, urlFor(0));
|
|
2435
|
-
for (let index = 1; index < manifest.length; index += 1) {
|
|
2436
|
-
await cdpClient.openBackgroundTab(urlFor(index));
|
|
2437
|
-
}
|
|
2438
|
-
return;
|
|
2439
|
-
}
|
|
2440
|
-
for (let index = openCount; index < manifest.length; index += 1) {
|
|
2441
|
-
await cdpClient.openBackgroundTab(urlFor(index));
|
|
2442
|
-
}
|
|
2443
|
-
};
|
|
2444
2325
|
const updateCheckStore = new UpdateCheckStore({
|
|
2445
2326
|
filePath: path.join(stateDirectory, UPDATE_CHECK_FILENAME),
|
|
2446
2327
|
currentVersion: options.currentVersion ?? readServerVersion(),
|
|
@@ -2476,8 +2357,6 @@ export const createServer = async (options = {}) => {
|
|
|
2476
2357
|
applyCdpPort,
|
|
2477
2358
|
getGraceSeconds,
|
|
2478
2359
|
applyGraceSeconds,
|
|
2479
|
-
getWorkspaceRestore,
|
|
2480
|
-
applyWorkspaceRestore,
|
|
2481
2360
|
broadcastThemes,
|
|
2482
2361
|
broadcastFonts,
|
|
2483
2362
|
connectCdpNow,
|
|
@@ -2779,13 +2658,6 @@ export const createServer = async (options = {}) => {
|
|
|
2779
2658
|
const targetId = cdpClient?.findTargetIdForToken(token);
|
|
2780
2659
|
if (targetId) {
|
|
2781
2660
|
wsToTargetId.set(ws, targetId);
|
|
2782
|
-
// A desktop tab just paired with CDP — arm a one-shot restore
|
|
2783
|
-
// for its (owner, windowId) so missing workspace tabs reopen
|
|
2784
|
-
// once the reconnection burst settles. Phone PWA tabs never pair
|
|
2785
|
-
// (no debug port), so restore stays scoped to the desktop.
|
|
2786
|
-
const profile = registry.clientProfile(ws);
|
|
2787
|
-
if (profile)
|
|
2788
|
-
scheduleWorkspaceRestore(profile.owner, profile.windowId);
|
|
2789
2661
|
}
|
|
2790
2662
|
}
|
|
2791
2663
|
safeSend(ws, {
|
|
@@ -2925,7 +2797,6 @@ export const createServer = async (options = {}) => {
|
|
|
2925
2797
|
if (stopPromise)
|
|
2926
2798
|
return stopPromise;
|
|
2927
2799
|
stopPromise = (async () => {
|
|
2928
|
-
flushWorkspaceSnapshot();
|
|
2929
2800
|
hibernateStore.write(await registry.hibernateEntries());
|
|
2930
2801
|
automationScheduler.dispose();
|
|
2931
2802
|
folderWatchManager.dispose();
|