@jlongo78/agent-spaces 1.0.0 → 1.0.2
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/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/build-manifest.json +3 -3
- package/.next/standalone/.next/prerender-manifest.json +3 -3
- package/.next/standalone/.next/server/app/(desktop)/admin/analytics/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/(desktop)/admin/analytics/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(desktop)/admin/users/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/(desktop)/admin/users/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(desktop)/analytics/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/(desktop)/analytics/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(desktop)/network/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/(desktop)/network/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(desktop)/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/(desktop)/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(desktop)/projects/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/(desktop)/projects/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(desktop)/sessions/[id]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/(desktop)/sessions/[id]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(desktop)/sessions/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/(desktop)/sessions/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(desktop)/settings/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/(desktop)/settings/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(desktop)/terminal/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/(desktop)/terminal/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(desktop)/terminal/pane/[id]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/(desktop)/terminal/pane/[id]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(desktop)/terminal/remote/[nodeId]/[workspaceId]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/(desktop)/terminal/remote/[nodeId]/[workspaceId]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(desktop)/workspaces/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/(desktop)/workspaces/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +1 -1
- package/.next/standalone/.next/server/app/_not-found.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/admin/analytics.html +1 -1
- package/.next/standalone/.next/server/app/admin/analytics.rsc +2 -2
- package/.next/standalone/.next/server/app/admin/analytics.segments/!KGRlc2t0b3Ap/admin/analytics/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/admin/analytics.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/admin/analytics.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/admin/users.html +1 -1
- package/.next/standalone/.next/server/app/admin/users.rsc +2 -2
- package/.next/standalone/.next/server/app/admin/users.segments/!KGRlc2t0b3Ap/admin/users/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/admin/users.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/admin/users.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/analytics.html +1 -1
- package/.next/standalone/.next/server/app/analytics.rsc +2 -2
- package/.next/standalone/.next/server/app/analytics.segments/!KGRlc2t0b3Ap/analytics/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/analytics.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/analytics.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/api/admin/analytics/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/admin/os-users/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/admin/users/[id]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/admin/users/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/analytics/overview/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/me/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/totp/setup/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/totp/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/totp/verify/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/bulk/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/chat/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/claude/usage/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/config/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/events/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/folders/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/discovered/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/handshake/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/health/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/identity/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/keys/[id]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/keys/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/nodes/[id]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/nodes/check/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/nodes/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/panes/[id]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/panes/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/projects/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/proxy/[nodeId]/[...path]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/search/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/sessions/[id]/messages/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/sessions/[id]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/sessions/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/workspaces/[id]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/workspaces/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/panes/[id]/diff/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/panes/[id]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/panes/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/proxy/models/[modelId]/[...path]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/proxy/models/[modelId]/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/search/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/server-config/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/sessions/[id]/chat/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/sessions/[id]/messages/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/sessions/[id]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/sessions/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/sync/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/tags/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/tier/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/updates/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/whisper/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wizard/chat/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/workspaces/[id]/context/[key]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/workspaces/[id]/context/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/workspaces/[id]/messages/[msgId]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/workspaces/[id]/messages/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/workspaces/[id]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/workspaces/[id]/sessions/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/workspaces/[id]/todos/[todoId]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/workspaces/[id]/todos/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/workspaces/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/login/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/login.html +1 -1
- package/.next/standalone/.next/server/app/login.rsc +2 -2
- package/.next/standalone/.next/server/app/login.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/login.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/login.segments/login/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/m/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/m/projects/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/m/projects/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/m/projects.html +1 -1
- package/.next/standalone/.next/server/app/m/projects.rsc +2 -2
- package/.next/standalone/.next/server/app/m/projects.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m/projects.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m/projects.segments/m/projects/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m/sessions/[id]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/m/sessions/[id]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/m/sessions/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/m/sessions/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/m/sessions.html +1 -1
- package/.next/standalone/.next/server/app/m/sessions.rsc +2 -2
- package/.next/standalone/.next/server/app/m/sessions.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m/sessions.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m/sessions.segments/m/sessions/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m/settings/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/m/settings/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/m/settings.html +1 -1
- package/.next/standalone/.next/server/app/m/settings.rsc +2 -2
- package/.next/standalone/.next/server/app/m/settings.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m/settings.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m/settings.segments/m/settings/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m/terminal/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/m/terminal/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/m/terminal.html +1 -1
- package/.next/standalone/.next/server/app/m/terminal.rsc +2 -2
- package/.next/standalone/.next/server/app/m/terminal.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m/terminal.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m/terminal.segments/m/terminal/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m.html +1 -1
- package/.next/standalone/.next/server/app/m.rsc +2 -2
- package/.next/standalone/.next/server/app/m.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m.segments/m/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/network.html +1 -1
- package/.next/standalone/.next/server/app/network.rsc +2 -2
- package/.next/standalone/.next/server/app/network.segments/!KGRlc2t0b3Ap/network/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/network.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/network.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/projects.html +1 -1
- package/.next/standalone/.next/server/app/projects.rsc +2 -2
- package/.next/standalone/.next/server/app/projects.segments/!KGRlc2t0b3Ap/projects/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/projects.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/projects.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/sessions.html +1 -1
- package/.next/standalone/.next/server/app/sessions.rsc +2 -2
- package/.next/standalone/.next/server/app/sessions.segments/!KGRlc2t0b3Ap/sessions/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/sessions.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/sessions.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/settings.html +1 -1
- package/.next/standalone/.next/server/app/settings.rsc +2 -2
- package/.next/standalone/.next/server/app/settings.segments/!KGRlc2t0b3Ap/settings/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/settings.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/terminal.html +1 -1
- package/.next/standalone/.next/server/app/terminal.rsc +2 -2
- package/.next/standalone/.next/server/app/terminal.segments/!KGRlc2t0b3Ap/terminal/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/terminal.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/terminal.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/vr/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/vr/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/vr.html +1 -1
- package/.next/standalone/.next/server/app/vr.rsc +2 -2
- package/.next/standalone/.next/server/app/vr.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/vr.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/vr.segments/vr/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/workspaces.html +1 -1
- package/.next/standalone/.next/server/app/workspaces.rsc +2 -2
- package/.next/standalone/.next/server/app/workspaces.segments/!KGRlc2t0b3Ap/workspaces/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/workspaces.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/workspaces.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/chunks/_1-inpovedul0t._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1yl1yt70hdi7k._.js +1 -1
- package/.next/standalone/.next/server/edge/chunks/[root-of-the-server]__00lhc9vpmf8oy._.js +1 -1
- package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
- package/.next/standalone/.next/server/middleware-manifest.json +5 -5
- package/.next/standalone/.next/server/pages/404.html +1 -1
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/server/preview-props.json +3 -3
- package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/static/chunks/07t-bv_pwp3nh.css +3 -0
- package/.next/standalone/package.json +6 -6
- package/README.md +29 -3
- package/bin/lib/cli-flags.js +2 -0
- package/bin/lib/remote.js +124 -15
- package/bin/lib/runtime/claude-sessions.js +108 -13
- package/bin/lib/runtime/index.js +1 -1
- package/bin/spaces.js +330 -57
- package/package.json +6 -6
- package/.next/standalone/.next/static/chunks/3bk2w5qzafz7n.css +0 -3
- /package/.next/standalone/.next/static/{_RTyuAfH-40lIlwVs2azh → B50xUMpZMRp2r4CxAPPFu}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{_RTyuAfH-40lIlwVs2azh → B50xUMpZMRp2r4CxAPPFu}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{_RTyuAfH-40lIlwVs2azh → B50xUMpZMRp2r4CxAPPFu}/_ssgManifest.js +0 -0
|
@@ -9,22 +9,33 @@
|
|
|
9
9
|
// conversation exactly. Guessing from the newest transcript in the pane's
|
|
10
10
|
// folder instead picks up any other Claude working in the same folder.
|
|
11
11
|
//
|
|
12
|
+
// Windows has no `ps`, and ancestry breaks there anyway: the `claude` shim
|
|
13
|
+
// is a shell script that `exec`s the real program, and Git Bash leaves a
|
|
14
|
+
// dead pid in the chain when it does. What every process in a pane does
|
|
15
|
+
// share is the pane's console, so on Windows the pane is found by asking
|
|
16
|
+
// which processes are attached to its console instead.
|
|
17
|
+
//
|
|
12
18
|
// Recorded so that a pane stopped by a server restart or a reboot resumes
|
|
13
19
|
// its conversation (pane.restart) rather than starting a new one.
|
|
14
20
|
|
|
15
21
|
const fs = require('fs');
|
|
16
22
|
const os = require('os');
|
|
17
23
|
const path = require('path');
|
|
18
|
-
const { execFile } = require('child_process');
|
|
24
|
+
const { execFile, fork } = require('child_process');
|
|
19
25
|
|
|
20
26
|
const POLL_MS = 5000;
|
|
21
27
|
// Deeper than any shell → wrapper → node → claude chain, and a bound on a
|
|
22
28
|
// corrupt table that loops.
|
|
23
29
|
const MAX_DEPTH = 32;
|
|
30
|
+
// A console-list helper that hangs is given up on; the pane stays unplaced
|
|
31
|
+
// and is looked at again next tick.
|
|
32
|
+
const CONSOLE_LIST_MS = 5000;
|
|
24
33
|
|
|
25
|
-
/**
|
|
26
|
-
|
|
27
|
-
|
|
34
|
+
/**
|
|
35
|
+
* pid → ppid from `ps`, or null when it cannot be read. `panes` is unused
|
|
36
|
+
* here; the Windows reader takes the same arguments.
|
|
37
|
+
*/
|
|
38
|
+
function readProcessTree(panes, callback, run = execFile) {
|
|
28
39
|
run('ps', ['-A', '-o', 'pid=,ppid='], { timeout: 3000 }, (error, stdout) => {
|
|
29
40
|
if (error) return callback(null);
|
|
30
41
|
const tree = new Map();
|
|
@@ -32,10 +43,59 @@ function readProcessTree(callback, run = execFile) {
|
|
|
32
43
|
const [pid, ppid] = line.trim().split(/\s+/).map(Number);
|
|
33
44
|
if (Number.isInteger(pid) && Number.isInteger(ppid)) tree.set(pid, ppid);
|
|
34
45
|
}
|
|
35
|
-
callback(tree);
|
|
46
|
+
callback(tree.size ? tree : null);
|
|
36
47
|
});
|
|
37
48
|
}
|
|
38
49
|
|
|
50
|
+
// node-pty ships this helper for its own kill(): it must run in a separate
|
|
51
|
+
// process, since a process can attach to only one console at a time.
|
|
52
|
+
function consoleListAgent() {
|
|
53
|
+
try { return require.resolve('node-pty/lib/conpty_console_list_agent'); } catch { return null; }
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** The pids attached to the console of `pid`, or [] when that cannot be read. */
|
|
57
|
+
function readConsoleProcesses(pid, callback, forkProcess = fork) {
|
|
58
|
+
const agentPath = consoleListAgent();
|
|
59
|
+
if (!agentPath) return callback([]);
|
|
60
|
+
let agent;
|
|
61
|
+
try {
|
|
62
|
+
agent = forkProcess(agentPath, [String(pid)], { stdio: ['ignore', 'ignore', 'ignore', 'ipc'], windowsHide: true });
|
|
63
|
+
} catch {
|
|
64
|
+
return callback([]);
|
|
65
|
+
}
|
|
66
|
+
let done = false;
|
|
67
|
+
const finish = (list) => {
|
|
68
|
+
if (done) return;
|
|
69
|
+
done = true;
|
|
70
|
+
clearTimeout(timer);
|
|
71
|
+
callback(list);
|
|
72
|
+
};
|
|
73
|
+
const timer = setTimeout(() => { try { agent.kill(); } catch { /* gone */ } finish([]); }, CONSOLE_LIST_MS);
|
|
74
|
+
agent.on('message', (m) => finish(Array.isArray(m?.consoleProcessList) ? m.consoleProcessList.filter(Number.isInteger) : []));
|
|
75
|
+
agent.on('error', () => finish([]));
|
|
76
|
+
agent.on('exit', () => finish([]));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* The Windows reader: a tree in which every process attached to a pane's
|
|
81
|
+
* console hangs directly off that pane's pid, so matchSessions needs one
|
|
82
|
+
* step. Null when no console could be read, so the watcher tries again.
|
|
83
|
+
*/
|
|
84
|
+
function readConsoleTree(panes, callback, readConsole = readConsoleProcesses) {
|
|
85
|
+
const shells = panes.filter(p => Number.isInteger(p.pid));
|
|
86
|
+
if (!shells.length) return callback(null);
|
|
87
|
+
const tree = new Map();
|
|
88
|
+
let pending = shells.length;
|
|
89
|
+
let anyRead = false;
|
|
90
|
+
for (const { pid } of shells) {
|
|
91
|
+
readConsole(pid, (list) => {
|
|
92
|
+
if (list.length) anyRead = true;
|
|
93
|
+
for (const member of list) if (member !== pid) tree.set(member, pid);
|
|
94
|
+
if (--pending === 0) callback(anyRead ? tree : null);
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
39
99
|
/** `{ pid, sessionId }` for every interactive Claude session file. */
|
|
40
100
|
function readClaudeSessions(home, fsMod = fs) {
|
|
41
101
|
const dir = path.join(home, '.claude', 'sessions');
|
|
@@ -86,23 +146,55 @@ function matchSessions(panes, sessions, tree) {
|
|
|
86
146
|
*/
|
|
87
147
|
function createClaudeSessionWatcher({
|
|
88
148
|
listPanes, onSession, home = os.homedir(), intervalMs = POLL_MS,
|
|
89
|
-
readTree =
|
|
149
|
+
readTree = process.platform === 'win32' ? readConsoleTree : readProcessTree,
|
|
150
|
+
readSessions = readClaudeSessions,
|
|
90
151
|
}) {
|
|
91
152
|
let busy = false;
|
|
153
|
+
// A process's parents are fixed when it starts, so a session's pid, once
|
|
154
|
+
// placed in a pane (or in none), needs no second look at the process
|
|
155
|
+
// table: /resume and /clear change the sessionId under the same pid.
|
|
156
|
+
// Forgotten when the set of panes changes, since a pane listed late may be
|
|
157
|
+
// the one a session already looked at belongs to.
|
|
158
|
+
const placed = new Map(); // pid → paneId | null
|
|
159
|
+
let placedFor = '';
|
|
160
|
+
|
|
161
|
+
function report(panes, found) {
|
|
162
|
+
for (const [paneId, sessionId] of found) {
|
|
163
|
+
const pane = panes.find(p => p.paneId === paneId);
|
|
164
|
+
if (pane && pane.sessionId !== sessionId) {
|
|
165
|
+
try { onSession(paneId, sessionId); } catch { /* bookkeeping only */ }
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
92
170
|
function tick() {
|
|
93
171
|
if (busy) return;
|
|
94
172
|
const panes = listPanes();
|
|
95
173
|
if (!panes.length) return;
|
|
174
|
+
const key = panes.map(p => `${p.paneId}:${p.pid}`).sort().join(',');
|
|
175
|
+
if (key !== placedFor) { placed.clear(); placedFor = key; }
|
|
176
|
+
const sessions = readSessions(home);
|
|
177
|
+
const current = new Set(sessions.map(s => s.pid));
|
|
178
|
+
for (const pid of placed.keys()) if (!current.has(pid)) placed.delete(pid);
|
|
179
|
+
|
|
180
|
+
const known = new Map();
|
|
181
|
+
for (const { pid, sessionId } of sessions) {
|
|
182
|
+
const paneId = placed.get(pid);
|
|
183
|
+
if (paneId) known.set(paneId, sessionId);
|
|
184
|
+
}
|
|
185
|
+
report(panes, known);
|
|
186
|
+
const unplaced = sessions.filter(s => !placed.has(s.pid));
|
|
187
|
+
if (!unplaced.length) return;
|
|
188
|
+
|
|
96
189
|
busy = true;
|
|
97
|
-
readTree((tree) => {
|
|
190
|
+
readTree(panes, (tree) => {
|
|
98
191
|
busy = false;
|
|
99
192
|
if (!tree) return;
|
|
100
|
-
for (const
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
try { onSession(paneId, sessionId); } catch { /* bookkeeping only */ }
|
|
104
|
-
}
|
|
193
|
+
for (const s of unplaced) {
|
|
194
|
+
const [paneId] = matchSessions(panes, [s], tree).keys();
|
|
195
|
+
placed.set(s.pid, paneId ?? null);
|
|
105
196
|
}
|
|
197
|
+
report(panes, matchSessions(panes, unplaced, tree));
|
|
106
198
|
});
|
|
107
199
|
}
|
|
108
200
|
const timer = setInterval(tick, intervalMs);
|
|
@@ -110,4 +202,7 @@ function createClaudeSessionWatcher({
|
|
|
110
202
|
return { tick, stop: () => clearInterval(timer) };
|
|
111
203
|
}
|
|
112
204
|
|
|
113
|
-
module.exports = {
|
|
205
|
+
module.exports = {
|
|
206
|
+
createClaudeSessionWatcher, matchSessions, readClaudeSessions,
|
|
207
|
+
readProcessTree, readConsoleTree, readConsoleProcesses,
|
|
208
|
+
};
|
package/bin/lib/runtime/index.js
CHANGED
|
@@ -1000,7 +1000,7 @@ function createRuntime({ nodeId = 'local', spacesDbPath, getApiPort, federationD
|
|
|
1000
1000
|
// spawnPane starts only the shell. A fresh pane gets its agent from
|
|
1001
1001
|
// the client's follow-up agent.start; a restart types it here, so the
|
|
1002
1002
|
// pane comes back running what it ran before with no second call.
|
|
1003
|
-
if (spawned.launchCommand) writePane(params.paneId, `${spawned.launchCommand}
|
|
1003
|
+
if (spawned.launchCommand) writePane(params.paneId, `${spawned.launchCommand}\r`);
|
|
1004
1004
|
return ok({ paneId: params.paneId, workspaceId, agentType, cwd, resumed: Boolean(agentSession), launchCommand: spawned.launchCommand });
|
|
1005
1005
|
}
|
|
1006
1006
|
|