@decibelsystems/tools 3.0.0 → 3.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/CHANGELOG.md +66 -0
- package/dist/agentCommands.d.ts +0 -1
- package/dist/agentCommands.d.ts.map +1 -1
- package/dist/agentCommands.js +19 -8
- package/dist/agentCommands.js.map +1 -1
- package/dist/agentPresence.d.ts +5 -3
- package/dist/agentPresence.d.ts.map +1 -1
- package/dist/agentPresence.js +20 -29
- package/dist/agentPresence.js.map +1 -1
- package/dist/architectAdrs.d.ts +13 -1
- package/dist/architectAdrs.d.ts.map +1 -1
- package/dist/architectAdrs.js +83 -1
- package/dist/architectAdrs.js.map +1 -1
- package/dist/artifacts.d.ts +60 -0
- package/dist/artifacts.d.ts.map +1 -0
- package/dist/artifacts.js +208 -0
- package/dist/artifacts.js.map +1 -0
- package/dist/asks.d.ts +93 -0
- package/dist/asks.d.ts.map +1 -0
- package/dist/asks.js +383 -0
- package/dist/asks.js.map +1 -0
- package/dist/chat.d.ts +47 -0
- package/dist/chat.d.ts.map +1 -0
- package/dist/chat.js +288 -0
- package/dist/chat.js.map +1 -0
- package/dist/daemon.d.ts +14 -3
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +44 -14
- package/dist/daemon.js.map +1 -1
- package/dist/daemonConfig.d.ts +22 -0
- package/dist/daemonConfig.d.ts.map +1 -1
- package/dist/daemonConfig.js +11 -0
- package/dist/daemonConfig.js.map +1 -1
- package/dist/domain/issue.d.ts +19 -15
- package/dist/domain/issue.d.ts.map +1 -1
- package/dist/domain/issue.js +4 -32
- package/dist/domain/issue.js.map +1 -1
- package/dist/domain/issueCodec.d.ts.map +1 -1
- package/dist/domain/issueCodec.js +10 -0
- package/dist/domain/issueCodec.js.map +1 -1
- package/dist/domain/issueRepository.d.ts +35 -2
- package/dist/domain/issueRepository.d.ts.map +1 -1
- package/dist/domain/issueRepository.js +40 -1
- package/dist/domain/issueRepository.js.map +1 -1
- package/dist/domain/uid.d.ts +16 -0
- package/dist/domain/uid.d.ts.map +1 -0
- package/dist/domain/uid.js +43 -0
- package/dist/domain/uid.js.map +1 -0
- package/dist/facades/definitions.d.ts.map +1 -1
- package/dist/facades/definitions.js +46 -3
- package/dist/facades/definitions.js.map +1 -1
- package/dist/hq/defineAgent.d.ts.map +1 -1
- package/dist/hq/defineAgent.js +7 -11
- package/dist/hq/defineAgent.js.map +1 -1
- package/dist/httpServer.d.ts.map +1 -1
- package/dist/httpServer.js +201 -48
- package/dist/httpServer.js.map +1 -1
- package/dist/identity.d.ts +123 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +312 -0
- package/dist/identity.js.map +1 -0
- package/dist/kernel.d.ts.map +1 -1
- package/dist/kernel.js +24 -1
- package/dist/kernel.js.map +1 -1
- package/dist/killSwitch.d.ts +117 -0
- package/dist/killSwitch.d.ts.map +1 -0
- package/dist/killSwitch.js +161 -0
- package/dist/killSwitch.js.map +1 -0
- package/dist/lib/atomicWrite.d.ts +23 -0
- package/dist/lib/atomicWrite.d.ts.map +1 -1
- package/dist/lib/atomicWrite.js +84 -0
- package/dist/lib/atomicWrite.js.map +1 -1
- package/dist/lib/recordIdAllocator.d.ts +21 -5
- package/dist/lib/recordIdAllocator.d.ts.map +1 -1
- package/dist/lib/recordIdAllocator.js +25 -7
- package/dist/lib/recordIdAllocator.js.map +1 -1
- package/dist/orgId.d.ts +23 -0
- package/dist/orgId.d.ts.map +1 -0
- package/dist/orgId.js +73 -0
- package/dist/orgId.js.map +1 -0
- package/dist/pairCli.d.ts +2 -0
- package/dist/pairCli.d.ts.map +1 -0
- package/dist/pairCli.js +97 -0
- package/dist/pairCli.js.map +1 -0
- package/dist/peerBroker.d.ts +40 -0
- package/dist/peerBroker.d.ts.map +1 -0
- package/dist/peerBroker.js +70 -0
- package/dist/peerBroker.js.map +1 -0
- package/dist/peerBrokerSupervisor.d.ts +21 -0
- package/dist/peerBrokerSupervisor.d.ts.map +1 -0
- package/dist/peerBrokerSupervisor.js +131 -0
- package/dist/peerBrokerSupervisor.js.map +1 -0
- package/dist/projectPaths.d.ts.map +1 -1
- package/dist/projectPaths.js +1 -19
- package/dist/projectPaths.js.map +1 -1
- package/dist/projectRegistry.d.ts +22 -0
- package/dist/projectRegistry.d.ts.map +1 -1
- package/dist/projectRegistry.js +58 -2
- package/dist/projectRegistry.js.map +1 -1
- package/dist/pty/boundary.d.ts +39 -0
- package/dist/pty/boundary.d.ts.map +1 -0
- package/dist/pty/boundary.js +100 -0
- package/dist/pty/boundary.js.map +1 -0
- package/dist/pty/errors.d.ts +6 -0
- package/dist/pty/errors.d.ts.map +1 -0
- package/dist/pty/errors.js +12 -0
- package/dist/pty/errors.js.map +1 -0
- package/dist/pty/fleet.d.ts +159 -0
- package/dist/pty/fleet.d.ts.map +1 -0
- package/dist/pty/fleet.js +543 -0
- package/dist/pty/fleet.js.map +1 -0
- package/dist/pty/launchProfile.d.ts +45 -0
- package/dist/pty/launchProfile.d.ts.map +1 -0
- package/dist/pty/launchProfile.js +149 -0
- package/dist/pty/launchProfile.js.map +1 -0
- package/dist/pty/openTerminal.d.ts +48 -0
- package/dist/pty/openTerminal.d.ts.map +1 -0
- package/dist/pty/openTerminal.js +185 -0
- package/dist/pty/openTerminal.js.map +1 -0
- package/dist/pty/pairDialog.d.ts +16 -0
- package/dist/pty/pairDialog.d.ts.map +1 -0
- package/dist/pty/pairDialog.js +121 -0
- package/dist/pty/pairDialog.js.map +1 -0
- package/dist/pty/pairing.d.ts +86 -0
- package/dist/pty/pairing.d.ts.map +1 -0
- package/dist/pty/pairing.js +351 -0
- package/dist/pty/pairing.js.map +1 -0
- package/dist/pty/routes.d.ts +49 -0
- package/dist/pty/routes.d.ts.map +1 -0
- package/dist/pty/routes.js +624 -0
- package/dist/pty/routes.js.map +1 -0
- package/dist/pty/sessions.d.ts +167 -0
- package/dist/pty/sessions.d.ts.map +1 -0
- package/dist/pty/sessions.js +513 -0
- package/dist/pty/sessions.js.map +1 -0
- package/dist/pty/tmux.d.ts +109 -0
- package/dist/pty/tmux.d.ts.map +1 -0
- package/dist/pty/tmux.js +271 -0
- package/dist/pty/tmux.js.map +1 -0
- package/dist/roster.d.ts +37 -0
- package/dist/roster.d.ts.map +1 -0
- package/dist/roster.js +126 -0
- package/dist/roster.js.map +1 -0
- package/dist/runtime/daemonMeta.d.ts +53 -0
- package/dist/runtime/daemonMeta.d.ts.map +1 -0
- package/dist/runtime/daemonMeta.js +121 -0
- package/dist/runtime/daemonMeta.js.map +1 -0
- package/dist/runtime/ensureRuntime.d.ts.map +1 -1
- package/dist/runtime/ensureRuntime.js +5 -10
- package/dist/runtime/ensureRuntime.js.map +1 -1
- package/dist/sentinelIssues.d.ts +16 -0
- package/dist/sentinelIssues.d.ts.map +1 -1
- package/dist/sentinelIssues.js +42 -1
- package/dist/sentinelIssues.js.map +1 -1
- package/dist/server.js +66 -5
- package/dist/server.js.map +1 -1
- package/dist/toolConfig.d.ts.map +1 -1
- package/dist/toolConfig.js +12 -0
- package/dist/toolConfig.js.map +1 -1
- package/dist/tools/agentic/agentQueue.d.ts.map +1 -1
- package/dist/tools/agentic/agentQueue.js +4 -0
- package/dist/tools/agentic/agentQueue.js.map +1 -1
- package/dist/tools/architect/index.d.ts +1 -0
- package/dist/tools/architect/index.d.ts.map +1 -1
- package/dist/tools/architect/index.js +45 -1
- package/dist/tools/architect/index.js.map +1 -1
- package/dist/tools/architect.d.ts.map +1 -1
- package/dist/tools/architect.js +59 -8
- package/dist/tools/architect.js.map +1 -1
- package/dist/tools/artifacts.d.ts +5 -0
- package/dist/tools/artifacts.d.ts.map +1 -0
- package/dist/tools/artifacts.js +89 -0
- package/dist/tools/artifacts.js.map +1 -0
- package/dist/tools/asks.d.ts +6 -0
- package/dist/tools/asks.d.ts.map +1 -0
- package/dist/tools/asks.js +104 -0
- package/dist/tools/asks.js.map +1 -0
- package/dist/tools/coordinator/index.d.ts +1 -0
- package/dist/tools/coordinator/index.d.ts.map +1 -1
- package/dist/tools/coordinator/index.js +42 -2
- package/dist/tools/coordinator/index.js.map +1 -1
- package/dist/tools/data-inspector.d.ts +1 -1
- package/dist/tools/data-inspector.d.ts.map +1 -1
- package/dist/tools/data-inspector.js +1 -1
- package/dist/tools/data-inspector.js.map +1 -1
- package/dist/tools/dojo/index.d.ts.map +1 -1
- package/dist/tools/dojo/index.js +52 -3
- package/dist/tools/dojo/index.js.map +1 -1
- package/dist/tools/dojo.d.ts +62 -1
- package/dist/tools/dojo.d.ts.map +1 -1
- package/dist/tools/dojo.js +84 -1
- package/dist/tools/dojo.js.map +1 -1
- package/dist/tools/guardian.d.ts +7 -0
- package/dist/tools/guardian.d.ts.map +1 -1
- package/dist/tools/guardian.js +146 -9
- package/dist/tools/guardian.js.map +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +6 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/killswitch/index.d.ts +13 -0
- package/dist/tools/killswitch/index.d.ts.map +1 -0
- package/dist/tools/killswitch/index.js +138 -0
- package/dist/tools/killswitch/index.js.map +1 -0
- package/dist/tools/oracle/index.d.ts.map +1 -1
- package/dist/tools/oracle/index.js +8 -0
- package/dist/tools/oracle/index.js.map +1 -1
- package/dist/tools/oracle.d.ts +7 -0
- package/dist/tools/oracle.d.ts.map +1 -1
- package/dist/tools/oracle.js +22 -6
- package/dist/tools/oracle.js.map +1 -1
- package/dist/tools/provenance.d.ts +11 -2
- package/dist/tools/provenance.d.ts.map +1 -1
- package/dist/tools/provenance.js +26 -24
- package/dist/tools/provenance.js.map +1 -1
- package/dist/tools/registry/index.d.ts.map +1 -1
- package/dist/tools/registry/index.js +24 -0
- package/dist/tools/registry/index.js.map +1 -1
- package/dist/tools/sentinel/index.d.ts.map +1 -1
- package/dist/tools/sentinel/index.js +54 -2
- package/dist/tools/sentinel/index.js.map +1 -1
- package/dist/tools/sentinel.d.ts +50 -0
- package/dist/tools/sentinel.d.ts.map +1 -1
- package/dist/tools/sentinel.js +72 -7
- package/dist/tools/sentinel.js.map +1 -1
- package/dist/tools/shared/runTracker.d.ts +2 -0
- package/dist/tools/shared/runTracker.d.ts.map +1 -1
- package/dist/tools/shared/runTracker.js +38 -0
- package/dist/tools/shared/runTracker.js.map +1 -1
- package/dist/tools/swarm.d.ts +3 -1
- package/dist/tools/swarm.d.ts.map +1 -1
- package/dist/tools/swarm.js +6 -12
- package/dist/tools/swarm.js.map +1 -1
- package/dist/tools/voice/index.d.ts +1 -0
- package/dist/tools/voice/index.d.ts.map +1 -1
- package/dist/tools/voice/index.js +33 -2
- package/dist/tools/voice/index.js.map +1 -1
- package/dist/tools/voice.d.ts +48 -1
- package/dist/tools/voice.d.ts.map +1 -1
- package/dist/tools/voice.js +63 -3
- package/dist/tools/voice.js.map +1 -1
- package/dist/transports/bridge.d.ts.map +1 -1
- package/dist/transports/bridge.js +2 -1
- package/dist/transports/bridge.js.map +1 -1
- package/dist/transports/mcp.d.ts.map +1 -1
- package/dist/transports/mcp.js +2 -1
- package/dist/transports/mcp.js.map +1 -1
- package/dist/version.d.ts +5 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +23 -0
- package/dist/version.js.map +1 -0
- package/package.json +13 -2
- package/templates/AGENT.md +3 -0
- package/templates/CLAUDE-decibel.md +11 -0
|
@@ -0,0 +1,513 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// Hosted sessions — list, spawn, control (ADR-0012 / decibel-hq EPIC-0015)
|
|
3
|
+
// ============================================================================
|
|
4
|
+
// Three kinds of row, distinguished by `origin`:
|
|
5
|
+
//
|
|
6
|
+
// spawned a tmux session the daemon started (name dcb-<project>-<6hex>).
|
|
7
|
+
// Owned: attach, interrupt, kill, resume.
|
|
8
|
+
// adopted a tmux session the user started, hosting a claude-peers session.
|
|
9
|
+
// Attach and interrupt only. The daemon never kills what it did not
|
|
10
|
+
// start.
|
|
11
|
+
// peer a live claude-peers session in a plain terminal tty. A daemon
|
|
12
|
+
// cannot attach to another terminal's pty, so attachable:false.
|
|
13
|
+
//
|
|
14
|
+
// Spawned sessions live on the daemon's own tmux server (`-L decibel`, see
|
|
15
|
+
// tmux.ts); Ben reaches one directly with `tmux -L decibel attach -t <key>`
|
|
16
|
+
// (default C-b prefix there: the owned server does not read ~/.tmux.conf).
|
|
17
|
+
// They run `claude --session-id <uuid>` with a uuid the daemon
|
|
18
|
+
// generates, so the resume id is known from birth rather than scraped from
|
|
19
|
+
// ~/.claude afterwards. remain-on-exit keeps the session after claude exits,
|
|
20
|
+
// which is what lets an exited session be listed and resumed in place.
|
|
21
|
+
//
|
|
22
|
+
// Spawn takes a project_id, never a cwd. The cwd comes from the registry, and
|
|
23
|
+
// only from an exact id/alias hit: resolveProjectPaths' later strategies fall
|
|
24
|
+
// back to the daemon's own cwd, and "start claude wherever the daemon happens
|
|
25
|
+
// to be" is not a resolution.
|
|
26
|
+
// ============================================================================
|
|
27
|
+
import { randomBytes, randomUUID } from 'crypto';
|
|
28
|
+
import { existsSync, chmodSync, statSync } from 'fs';
|
|
29
|
+
import { homedir } from 'os';
|
|
30
|
+
import { dirname, join } from 'path';
|
|
31
|
+
import { createRequire } from 'module';
|
|
32
|
+
import { listProjects } from '../projectRegistry.js';
|
|
33
|
+
import { fetchPeers, getHumanPeerId } from '../peerBroker.js';
|
|
34
|
+
import { log } from '../config.js';
|
|
35
|
+
import { SessionError } from './errors.js';
|
|
36
|
+
import { SPAWNED_PREFIX, tmux, listSessions, findSession, paneTtyMap, serverFor, sessionTarget, paneTarget, cleanLabel, resolveTmux, isNoServer, unsetDaemonEnvArgs, OWNED_SOCKET_DEFAULT, TITLE_FORMAT, } from './tmux.js';
|
|
37
|
+
import { loadLaunchProfile, profileArgs, tmuxOptionArgs } from './launchProfile.js';
|
|
38
|
+
let ptyModule;
|
|
39
|
+
export async function loadPty() {
|
|
40
|
+
if (ptyModule !== undefined)
|
|
41
|
+
return ptyModule;
|
|
42
|
+
try {
|
|
43
|
+
const mod = (await import('node-pty'));
|
|
44
|
+
ptyModule = (mod.default ?? mod);
|
|
45
|
+
ensureSpawnHelperExecutable();
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
log(`Sessions: node-pty unavailable, attach disabled (${err instanceof Error ? err.message : String(err)})`);
|
|
49
|
+
ptyModule = null;
|
|
50
|
+
}
|
|
51
|
+
return ptyModule;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* npm unpacks node-pty's prebuilt spawn-helper without the exec bit on some
|
|
55
|
+
* installs, and every spawn then fails with a bare "posix_spawnp failed".
|
|
56
|
+
*/
|
|
57
|
+
function ensureSpawnHelperExecutable() {
|
|
58
|
+
if (process.platform === 'win32')
|
|
59
|
+
return;
|
|
60
|
+
try {
|
|
61
|
+
const req = createRequire(import.meta.url);
|
|
62
|
+
const root = dirname(req.resolve('node-pty/package.json'));
|
|
63
|
+
const candidates = [
|
|
64
|
+
join(root, 'prebuilds', `${process.platform}-${process.arch}`, 'spawn-helper'),
|
|
65
|
+
join(root, 'build', 'Release', 'spawn-helper'),
|
|
66
|
+
];
|
|
67
|
+
for (const helper of candidates) {
|
|
68
|
+
if (existsSync(helper) && (statSync(helper).mode & 0o111) === 0) {
|
|
69
|
+
chmodSync(helper, 0o755);
|
|
70
|
+
log(`Sessions: made ${helper} executable`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
// Best effort; a real failure surfaces at spawn with its own message.
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
export { SessionError };
|
|
79
|
+
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
80
|
+
export function isUuid(v) {
|
|
81
|
+
return typeof v === 'string' && UUID_RE.test(v);
|
|
82
|
+
}
|
|
83
|
+
/** Exact id or alias in projects.json, available on this device. Nothing else. */
|
|
84
|
+
export function resolveRegisteredProject(projectId) {
|
|
85
|
+
const projects = listProjects();
|
|
86
|
+
const hit = projects.find((p) => p.id === projectId) ?? projects.find((p) => p.aliases?.includes(projectId));
|
|
87
|
+
if (!hit) {
|
|
88
|
+
const known = projects.map((p) => p.id).join(', ') || '(none)';
|
|
89
|
+
throw new SessionError(404, 'PROJECT_NOT_FOUND', `Project "${projectId}" is not in the registry. Hosted sessions only start in registered projects. ` +
|
|
90
|
+
`Registered: ${known}. To fix: registry_add (or project_init) the project first.`);
|
|
91
|
+
}
|
|
92
|
+
if (hit.available === false || !existsSync(hit.path)) {
|
|
93
|
+
throw new SessionError(409, 'PROJECT_UNAVAILABLE', `Project "${hit.id}" is registered but its path is not available on this device (${hit.path}).`);
|
|
94
|
+
}
|
|
95
|
+
return { id: hit.id, path: hit.path };
|
|
96
|
+
}
|
|
97
|
+
export function isWithin(child, parent) {
|
|
98
|
+
const p = parent.replace(/\/+$/, '');
|
|
99
|
+
return child === p || child.startsWith(p + '/');
|
|
100
|
+
}
|
|
101
|
+
/** Every registered project available on this device. */
|
|
102
|
+
export function availableProjects() {
|
|
103
|
+
return listProjects()
|
|
104
|
+
.filter((p) => p.available !== false)
|
|
105
|
+
.map((p) => ({ id: p.id, path: p.path }));
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* The registered project a path belongs to: the LONGEST registered path that
|
|
109
|
+
* contains it, so a checkout nested inside another project belongs to itself.
|
|
110
|
+
* Undefined when nothing contains it (a session in ~/Documents/GitHub itself,
|
|
111
|
+
* or in a repo that was never registered).
|
|
112
|
+
*/
|
|
113
|
+
export function projectForPath(path, projects) {
|
|
114
|
+
let best;
|
|
115
|
+
for (const p of projects) {
|
|
116
|
+
if (isWithin(path, p.path) && (!best || p.path.length > best.path.length))
|
|
117
|
+
best = p;
|
|
118
|
+
}
|
|
119
|
+
return best;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* The session roster. With a project id, that project's sessions only (and an
|
|
123
|
+
* unregistered id is an error, never a fallback). Without one, every session
|
|
124
|
+
* on the machine; `project_id` is present where the session resolves to a
|
|
125
|
+
* registered project and omitted where it does not.
|
|
126
|
+
*/
|
|
127
|
+
export async function listHostedSessions(projectId, deps = {}) {
|
|
128
|
+
const scope = projectId ? resolveRegisteredProject(projectId) : undefined;
|
|
129
|
+
const projects = (deps.projects ?? availableProjects)();
|
|
130
|
+
const [sessions, userSessions, ttyMap, peers, ptyOk] = await Promise.all([
|
|
131
|
+
(deps.ownedSessions ?? (() => listSessions('owned')))(),
|
|
132
|
+
(deps.userSessions ?? (() => listSessions('user')))(),
|
|
133
|
+
(deps.ttyMap ?? paneTtyMap)(),
|
|
134
|
+
(deps.peers ?? fetchPeers)(),
|
|
135
|
+
(deps.ptyAvailable ?? (async () => (await loadPty()) !== null))(),
|
|
136
|
+
]);
|
|
137
|
+
const rows = new Map();
|
|
138
|
+
for (const s of sessions) {
|
|
139
|
+
if (!s.name.startsWith(SPAWNED_PREFIX))
|
|
140
|
+
continue;
|
|
141
|
+
if (scope && s.project_id !== scope.id)
|
|
142
|
+
continue;
|
|
143
|
+
const row = {
|
|
144
|
+
session_key: s.name,
|
|
145
|
+
...(s.project_id ? { project_id: s.project_id } : {}),
|
|
146
|
+
origin: 'spawned',
|
|
147
|
+
state: s.dead ? 'exited' : 'live',
|
|
148
|
+
attachable: !s.dead && ptyOk,
|
|
149
|
+
};
|
|
150
|
+
if (!s.dead) {
|
|
151
|
+
row.attach_handle = `tmux:${s.name}`;
|
|
152
|
+
row.attach_argv = attachArgv(s.name);
|
|
153
|
+
}
|
|
154
|
+
else if (s.claude_session_id)
|
|
155
|
+
row.attach_handle = `resume:${s.claude_session_id}`;
|
|
156
|
+
if (s.claude_session_id)
|
|
157
|
+
row.claude_session_id = s.claude_session_id;
|
|
158
|
+
if (s.cwd)
|
|
159
|
+
row.cwd = s.cwd;
|
|
160
|
+
if (s.branch)
|
|
161
|
+
row.branch = s.branch;
|
|
162
|
+
if (s.issue_label)
|
|
163
|
+
row.issue_label = s.issue_label;
|
|
164
|
+
if (s.created)
|
|
165
|
+
row.created = s.created;
|
|
166
|
+
rows.set(s.name, row);
|
|
167
|
+
}
|
|
168
|
+
const sessionByName = new Map(userSessions.map((s) => [s.name, s]));
|
|
169
|
+
const humanPeer = getHumanPeerId();
|
|
170
|
+
for (const peer of peers) {
|
|
171
|
+
// The HQ chat peer stands for the human, not a session (src/chat.ts).
|
|
172
|
+
if (humanPeer && peer.id === humanPeer)
|
|
173
|
+
continue;
|
|
174
|
+
const tmuxName = peer.tty ? ttyMap.get(peer.tty) : undefined;
|
|
175
|
+
const peerFields = { peer_id: peer.id };
|
|
176
|
+
if (peer.pid)
|
|
177
|
+
peerFields.pid = peer.pid;
|
|
178
|
+
if (peer.tty)
|
|
179
|
+
peerFields.tty = peer.tty;
|
|
180
|
+
if (peer.summary)
|
|
181
|
+
peerFields.summary = peer.summary;
|
|
182
|
+
// The claude running inside a spawned session: fold it into that row
|
|
183
|
+
// rather than listing the same session twice.
|
|
184
|
+
if (tmuxName && rows.has(tmuxName)) {
|
|
185
|
+
Object.assign(rows.get(tmuxName), peerFields);
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
// A spawned session filtered out by scope (another project).
|
|
189
|
+
if (tmuxName && tmuxName.startsWith(SPAWNED_PREFIX))
|
|
190
|
+
continue;
|
|
191
|
+
const root = peer.git_root || peer.cwd;
|
|
192
|
+
const project = root ? projectForPath(root, projects) : undefined;
|
|
193
|
+
if (scope && project?.id !== scope.id)
|
|
194
|
+
continue;
|
|
195
|
+
const projectField = project ? { project_id: project.id } : {};
|
|
196
|
+
if (tmuxName) {
|
|
197
|
+
const s = sessionByName.get(tmuxName);
|
|
198
|
+
rows.set(tmuxName, {
|
|
199
|
+
session_key: tmuxName,
|
|
200
|
+
...projectField,
|
|
201
|
+
origin: 'adopted',
|
|
202
|
+
state: 'live',
|
|
203
|
+
attachable: ptyOk,
|
|
204
|
+
attach_handle: `tmux:${tmuxName}`,
|
|
205
|
+
...(peer.cwd ? { cwd: peer.cwd } : {}),
|
|
206
|
+
...(s?.created ? { created: s.created } : {}),
|
|
207
|
+
...peerFields,
|
|
208
|
+
});
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
rows.set(peer.id, {
|
|
212
|
+
session_key: peer.id,
|
|
213
|
+
...projectField,
|
|
214
|
+
origin: 'peer',
|
|
215
|
+
state: 'live',
|
|
216
|
+
attachable: false,
|
|
217
|
+
...(peer.cwd ? { cwd: peer.cwd } : {}),
|
|
218
|
+
...(peer.registered_at ? { created: peer.registered_at } : {}),
|
|
219
|
+
...peerFields,
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
return [...rows.values()];
|
|
223
|
+
}
|
|
224
|
+
// ----------------------------------------------------------------------------
|
|
225
|
+
// Attach eligibility
|
|
226
|
+
// ----------------------------------------------------------------------------
|
|
227
|
+
/**
|
|
228
|
+
* What an attach token may be minted for: a live spawned session, or a tmux
|
|
229
|
+
* session that is hosting a claude-peers session. Never an arbitrary tmux
|
|
230
|
+
* session — the user's other tmux work is not HQ's to open.
|
|
231
|
+
*/
|
|
232
|
+
export async function resolveAttachable(key) {
|
|
233
|
+
const s = await findSession(key);
|
|
234
|
+
if (!s)
|
|
235
|
+
throw new SessionError(404, 'SESSION_NOT_FOUND', `No tmux session "${key}".`);
|
|
236
|
+
if (s.dead)
|
|
237
|
+
throw new SessionError(409, 'SESSION_EXITED', `Session "${key}" has exited; resume it first.`);
|
|
238
|
+
if (key.startsWith(SPAWNED_PREFIX))
|
|
239
|
+
return s;
|
|
240
|
+
const [ttyMap, peers] = await Promise.all([paneTtyMap(), fetchPeers()]);
|
|
241
|
+
const hosted = peers.some((p) => p.tty && ttyMap.get(p.tty) === key);
|
|
242
|
+
if (!hosted) {
|
|
243
|
+
throw new SessionError(403, 'NOT_A_CLAUDE_SESSION', `tmux session "${key}" is not hosting a Claude session.`);
|
|
244
|
+
}
|
|
245
|
+
return s;
|
|
246
|
+
}
|
|
247
|
+
// ----------------------------------------------------------------------------
|
|
248
|
+
// Spawn / control
|
|
249
|
+
// ----------------------------------------------------------------------------
|
|
250
|
+
/**
|
|
251
|
+
* launchd gives the daemon no login PATH. Find claude by absolute path, then
|
|
252
|
+
* run it under a login shell so it gets the user's environment.
|
|
253
|
+
*/
|
|
254
|
+
export function resolveClaude() {
|
|
255
|
+
const home = homedir();
|
|
256
|
+
const candidates = [
|
|
257
|
+
process.env.DECIBEL_CLAUDE_BIN,
|
|
258
|
+
join(home, '.npm-global', 'bin', 'claude'),
|
|
259
|
+
join(home, '.claude', 'local', 'claude'),
|
|
260
|
+
join(home, '.local', 'bin', 'claude'),
|
|
261
|
+
'/opt/homebrew/bin/claude',
|
|
262
|
+
'/usr/local/bin/claude',
|
|
263
|
+
].filter((p) => !!p);
|
|
264
|
+
return candidates.find((p) => existsSync(p)) ?? 'claude';
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* argv for the pane: `$SHELL -lc 'exec "$0" "$@"' <claude> <args...>`. The
|
|
268
|
+
* claude path and arguments travel as positional parameters, so nothing is
|
|
269
|
+
* interpolated into the shell script.
|
|
270
|
+
*/
|
|
271
|
+
export function claudeCommand(claudeArgs) {
|
|
272
|
+
const shell = process.env.SHELL && existsSync(process.env.SHELL) ? process.env.SHELL : '/bin/zsh';
|
|
273
|
+
return [shell, '-lc', 'exec "$0" "$@"', resolveClaude(), ...claudeArgs];
|
|
274
|
+
}
|
|
275
|
+
export function sessionNameFor(projectId) {
|
|
276
|
+
const slug = projectId.toLowerCase().replace(/[^a-z0-9-]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 32) || 'project';
|
|
277
|
+
return `${SPAWNED_PREFIX}${slug}-${randomBytes(3).toString('hex')}`;
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* The argv for attaching to an owned session from a terminal (ADR-0018). The
|
|
281
|
+
* absolute tmux path, because launchd's PATH and a login shell's can resolve
|
|
282
|
+
* different binaries, and a client/server version mismatch refuses to attach.
|
|
283
|
+
* `=key` is an exact-match target. Not secret.
|
|
284
|
+
*/
|
|
285
|
+
export function attachArgv(key) {
|
|
286
|
+
return [resolveTmux(), '-u', '-L', process.env.DECIBEL_TMUX_SOCKET || OWNED_SOCKET_DEFAULT, 'attach-session', '-t', sessionTarget(key)];
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Apply launch.json's tmux options to the owned server, if it is running.
|
|
290
|
+
* Spawns apply them too; this covers a daemon restart, where the tmux server
|
|
291
|
+
* and its sessions outlive the daemon. A missing server or a bad launch.json
|
|
292
|
+
* is logged, never thrown: the daemon must still boot.
|
|
293
|
+
*/
|
|
294
|
+
export async function applyTmuxProfile() {
|
|
295
|
+
let profile;
|
|
296
|
+
try {
|
|
297
|
+
profile = loadLaunchProfile();
|
|
298
|
+
}
|
|
299
|
+
catch (err) {
|
|
300
|
+
log(`Sessions: tmux options not applied: ${err instanceof Error ? err.message : String(err)}`);
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
const unset = unsetDaemonEnvArgs();
|
|
304
|
+
const r = await tmux('owned', [...tmuxOptionArgs(profile.tmux), ...(unset.length ? [';', ...unset] : [])]);
|
|
305
|
+
if (!r.ok && !isNoServer(r.stderr))
|
|
306
|
+
log(`Sessions: tmux options not applied: ${r.stderr.trim()}`);
|
|
307
|
+
}
|
|
308
|
+
/** The largest single scroll step a client may ask for. */
|
|
309
|
+
const MAX_SCROLL_LINES = 10_000;
|
|
310
|
+
/**
|
|
311
|
+
* Scroll a session's pane through tmux copy-mode, for a client with no
|
|
312
|
+
* scrollback of its own (HQ's xterm.js pane: tmux draws on the alternate
|
|
313
|
+
* screen, and the owned server runs with mouse off). Never a keystroke into
|
|
314
|
+
* the session: copy-mode is tmux's own view.
|
|
315
|
+
*
|
|
316
|
+
* {lines: n<0} enter copy-mode -e and scroll up |n| lines
|
|
317
|
+
* {lines: n>0} scroll down; -e leaves copy-mode at the bottom by itself
|
|
318
|
+
* {cancel: true} leave copy-mode
|
|
319
|
+
*
|
|
320
|
+
* Down and cancel do nothing when the pane is not in copy-mode. HQ's line
|
|
321
|
+
* counter can overcount past the top of history, and it sends cancel before
|
|
322
|
+
* the first keystroke after any scroll, so both arrive when nothing is
|
|
323
|
+
* scrolled. tmux answers "not in a mode" then, which is the no-op.
|
|
324
|
+
*/
|
|
325
|
+
export async function scrollPane(key, frame) {
|
|
326
|
+
const server = serverFor(key);
|
|
327
|
+
const pane = paneTarget(key);
|
|
328
|
+
let args;
|
|
329
|
+
if (frame.cancel === true) {
|
|
330
|
+
args = ['send-keys', '-X', '-t', pane, 'cancel'];
|
|
331
|
+
}
|
|
332
|
+
else {
|
|
333
|
+
const n = Math.trunc(Number(frame.lines));
|
|
334
|
+
if (!Number.isFinite(n) || n === 0)
|
|
335
|
+
return;
|
|
336
|
+
const count = String(Math.min(Math.abs(n), MAX_SCROLL_LINES));
|
|
337
|
+
args = n < 0
|
|
338
|
+
? ['copy-mode', '-e', '-t', pane, ';', 'send-keys', '-X', '-N', count, '-t', pane, 'scroll-up']
|
|
339
|
+
: ['send-keys', '-X', '-N', count, '-t', pane, 'scroll-down'];
|
|
340
|
+
}
|
|
341
|
+
const r = await tmux(server, args);
|
|
342
|
+
if (!r.ok && !/not in a mode/.test(r.stderr)) {
|
|
343
|
+
log(`Sessions: scroll on ${key} failed: ${r.stderr.trim()}`);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
export async function spawnSession(input, internal = {}) {
|
|
347
|
+
if (typeof input.project_id !== 'string' || !input.project_id) {
|
|
348
|
+
throw new SessionError(400, 'BAD_REQUEST', 'project_id is required.');
|
|
349
|
+
}
|
|
350
|
+
if (input.resume !== undefined && !isUuid(input.resume)) {
|
|
351
|
+
throw new SessionError(400, 'BAD_REQUEST', 'resume must be a Claude session uuid.');
|
|
352
|
+
}
|
|
353
|
+
// Before touching tmux: a broken launch.json refuses every spawn rather
|
|
354
|
+
// than starting claude without the flags Ben chose.
|
|
355
|
+
const profile = loadLaunchProfile();
|
|
356
|
+
const project = resolveRegisteredProject(input.project_id);
|
|
357
|
+
let cwd = project.path;
|
|
358
|
+
if (internal.cwd !== undefined) {
|
|
359
|
+
if (!isWithin(internal.cwd, project.path) || !existsSync(internal.cwd)) {
|
|
360
|
+
throw new SessionError(409, 'CWD_UNAVAILABLE', `"${internal.cwd}" is not an existing directory inside project "${project.id}".`);
|
|
361
|
+
}
|
|
362
|
+
cwd = internal.cwd;
|
|
363
|
+
}
|
|
364
|
+
const name = sessionNameFor(project.id);
|
|
365
|
+
const uuid = input.resume ?? randomUUID();
|
|
366
|
+
const claudeArgs = [...(input.resume ? ['--resume', uuid] : ['--session-id', uuid]), ...profileArgs(profile)];
|
|
367
|
+
const options = [
|
|
368
|
+
['@dcb_project', project.id],
|
|
369
|
+
['@dcb_uuid', uuid],
|
|
370
|
+
['@dcb_cwd', cwd],
|
|
371
|
+
['@dcb_branch', cleanLabel(input.branch)],
|
|
372
|
+
['@dcb_issue', cleanLabel(input.issue_label)],
|
|
373
|
+
];
|
|
374
|
+
// Start on a placeholder, set the options and remain-on-exit, THEN respawn the
|
|
375
|
+
// pane into claude. Starting claude directly races remain-on-exit: a claude
|
|
376
|
+
// that exits in milliseconds (bad flag, env refusal) takes the session with
|
|
377
|
+
// it before the option lands, and there is nothing left to report or resume.
|
|
378
|
+
// One tmux invocation; a lone ';' argument separates the commands.
|
|
379
|
+
// The profile's tmux options (history-limit, mouse) go first, as global
|
|
380
|
+
// options: a pane's history-limit is fixed when new-session creates it, and
|
|
381
|
+
// the owned server never reads ~/.tmux.conf (ISS-0205).
|
|
382
|
+
const unset = unsetDaemonEnvArgs();
|
|
383
|
+
const args = [...tmuxOptionArgs(profile.tmux), ';', ...(unset.length ? [...unset, ';'] : []),
|
|
384
|
+
'new-session', '-d', '-s', name, '-c', cwd, '-x', '120', '-y', '32', 'sleep', '86400'];
|
|
385
|
+
for (const [opt, val] of options) {
|
|
386
|
+
if (val !== undefined)
|
|
387
|
+
args.push(';', 'set-option', '-t', paneTarget(name), opt, val);
|
|
388
|
+
}
|
|
389
|
+
args.push(';', 'set-option', '-w', '-t', paneTarget(name), 'remain-on-exit', 'on');
|
|
390
|
+
// HQ's 120x32 pane and a Ghostty tab can be attached at once; without this
|
|
391
|
+
// tmux shrinks the window to the smallest client. The client that typed
|
|
392
|
+
// last sets the size instead.
|
|
393
|
+
args.push(';', 'set-option', '-w', '-t', paneTarget(name), 'window-size', 'latest');
|
|
394
|
+
// tmux's status bar means nothing inside HQ's pane.
|
|
395
|
+
args.push(';', 'set-option', '-t', paneTarget(name), 'status', 'off');
|
|
396
|
+
// Claude Code asks for focus events and warns inside the pane without them.
|
|
397
|
+
// Server-scoped; setting it on every spawn keeps a restarted server right.
|
|
398
|
+
args.push(';', 'set-option', '-s', 'focus-events', 'on');
|
|
399
|
+
// Clients get the repo as their terminal title (a Ghostty tab, HQ's pane).
|
|
400
|
+
// Global, so sessions spawned before a daemon restart keep it too.
|
|
401
|
+
args.push(';', 'set-option', '-g', 'set-titles', 'on', ';', 'set-option', '-g', 'set-titles-string', TITLE_FORMAT);
|
|
402
|
+
args.push(';', 'respawn-pane', '-k', '-t', paneTarget(name), '-c', cwd, ...claudeCommand(claudeArgs));
|
|
403
|
+
const r = await tmux('owned', args, 10_000);
|
|
404
|
+
if (!r.ok) {
|
|
405
|
+
throw new SessionError(500, 'SPAWN_FAILED', `tmux could not start the session: ${r.stderr.trim() || 'unknown error'}`);
|
|
406
|
+
}
|
|
407
|
+
log(`Sessions: spawned ${name} in ${project.id}${input.resume ? ' (resume)' : ''}`);
|
|
408
|
+
const result = { session_key: name, claude_session_id: uuid, attach_argv: attachArgv(name) };
|
|
409
|
+
const attention = await confirmIfNeeded(name, profile);
|
|
410
|
+
if (attention)
|
|
411
|
+
result.needs_attention = attention;
|
|
412
|
+
return result;
|
|
413
|
+
}
|
|
414
|
+
export const DIALOG_TIMEOUT_MS = 15_000;
|
|
415
|
+
const DIALOG_POLL_MS = 250;
|
|
416
|
+
/** Exact match for the dev-channels warning, cursor on "1.". */
|
|
417
|
+
export function isDevChannelsDialog(screen) {
|
|
418
|
+
return (screen.includes('Loading development channels') &&
|
|
419
|
+
screen.includes('I am using this for local development') &&
|
|
420
|
+
/^[\s│|]*❯\s*1\./m.test(screen));
|
|
421
|
+
}
|
|
422
|
+
/** Null when confirmed; the attention code and message otherwise. */
|
|
423
|
+
export async function confirmDevChannels(key, deps = {}) {
|
|
424
|
+
const capture = deps.capture ?? (async (k) => {
|
|
425
|
+
const r = await tmux('owned', ['capture-pane', '-p', '-t', paneTarget(k)]);
|
|
426
|
+
return r.ok ? r.stdout : null;
|
|
427
|
+
});
|
|
428
|
+
const isDead = deps.isDead ?? (async (k) => {
|
|
429
|
+
const r = await tmux('owned', ['display-message', '-p', '-t', paneTarget(k), '#{pane_dead}']);
|
|
430
|
+
return r.ok && r.stdout.trim() === '1';
|
|
431
|
+
});
|
|
432
|
+
const sendEnter = deps.sendEnter ?? (async (k) => (await tmux('owned', ['send-keys', '-t', paneTarget(k), 'Enter'])).ok);
|
|
433
|
+
const sleep = deps.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
434
|
+
const now = deps.now ?? Date.now;
|
|
435
|
+
const deadline = now() + (deps.timeoutMs ?? DIALOG_TIMEOUT_MS);
|
|
436
|
+
let last = '';
|
|
437
|
+
while (now() < deadline) {
|
|
438
|
+
const screen = await capture(key);
|
|
439
|
+
if (screen !== null) {
|
|
440
|
+
last = screen;
|
|
441
|
+
if (isDevChannelsDialog(screen)) {
|
|
442
|
+
if (!(await sendEnter(key))) {
|
|
443
|
+
return { code: 'DIALOG_UNRECOGNISED', error: 'The dev-channels dialog showed, but the Enter could not be sent.' };
|
|
444
|
+
}
|
|
445
|
+
log(`Sessions: confirmed the dev-channels dialog in ${key}`);
|
|
446
|
+
return null;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
if (await isDead(key)) {
|
|
450
|
+
return { code: 'CLAUDE_EXITED', error: 'claude exited before the dev-channels dialog appeared. Attach to read why.' };
|
|
451
|
+
}
|
|
452
|
+
await sleep(DIALOG_POLL_MS);
|
|
453
|
+
}
|
|
454
|
+
return last.trim()
|
|
455
|
+
? { code: 'DIALOG_UNRECOGNISED', error: 'The screen did not match the dev-channels dialog, so no key was pressed. Attach and answer it.' }
|
|
456
|
+
: { code: 'DIALOG_TIMEOUT', error: 'Nothing appeared within 15 s. Attach to check the session.' };
|
|
457
|
+
}
|
|
458
|
+
/** Run D4 only when the profile loads dev channels. */
|
|
459
|
+
async function confirmIfNeeded(key, profile) {
|
|
460
|
+
if (!profile.dev_channels.length)
|
|
461
|
+
return null;
|
|
462
|
+
const attention = await confirmDevChannels(key);
|
|
463
|
+
if (attention)
|
|
464
|
+
log(`Sessions: ${key} needs attention (${attention.code})`);
|
|
465
|
+
return attention;
|
|
466
|
+
}
|
|
467
|
+
export async function controlSession(key, action) {
|
|
468
|
+
if (action !== 'interrupt' && action !== 'kill' && action !== 'resume') {
|
|
469
|
+
throw new SessionError(400, 'BAD_REQUEST', 'action must be one of interrupt, kill, resume.');
|
|
470
|
+
}
|
|
471
|
+
const s = await findSession(key);
|
|
472
|
+
if (!s)
|
|
473
|
+
throw new SessionError(404, 'SESSION_NOT_FOUND', `No tmux session "${key}".`);
|
|
474
|
+
const owned = serverFor(key) === 'owned';
|
|
475
|
+
if (action === 'interrupt') {
|
|
476
|
+
if (!owned)
|
|
477
|
+
await resolveAttachable(key); // adopted: must be hosting claude
|
|
478
|
+
if (s.dead)
|
|
479
|
+
throw new SessionError(409, 'SESSION_EXITED', `Session "${key}" has exited.`);
|
|
480
|
+
const r = await tmux(serverFor(key), ['send-keys', '-t', paneTarget(key), 'C-c']);
|
|
481
|
+
if (!r.ok)
|
|
482
|
+
throw new SessionError(500, 'CONTROL_FAILED', r.stderr.trim());
|
|
483
|
+
return { ok: true, action };
|
|
484
|
+
}
|
|
485
|
+
if (!owned) {
|
|
486
|
+
throw new SessionError(403, 'NOT_OWNED', `"${key}" was not started by the daemon; only interrupt is allowed.`);
|
|
487
|
+
}
|
|
488
|
+
if (action === 'kill') {
|
|
489
|
+
const r = await tmux('owned', ['kill-session', '-t', sessionTarget(key)]);
|
|
490
|
+
if (!r.ok)
|
|
491
|
+
throw new SessionError(500, 'CONTROL_FAILED', r.stderr.trim());
|
|
492
|
+
log(`Sessions: killed ${key}`);
|
|
493
|
+
return { ok: true, action };
|
|
494
|
+
}
|
|
495
|
+
// resume
|
|
496
|
+
if (!s.dead)
|
|
497
|
+
throw new SessionError(409, 'SESSION_LIVE', `Session "${key}" is still running.`);
|
|
498
|
+
if (!isUuid(s.claude_session_id)) {
|
|
499
|
+
throw new SessionError(409, 'NO_RESUME_ID', `Session "${key}" has no Claude session id to resume.`);
|
|
500
|
+
}
|
|
501
|
+
const profile = loadLaunchProfile();
|
|
502
|
+
const cwd = s.cwd && existsSync(s.cwd) ? s.cwd : s.project_id ? resolveRegisteredProject(s.project_id).path : homedir();
|
|
503
|
+
const r = await tmux('owned', [
|
|
504
|
+
'respawn-pane', '-k', '-t', paneTarget(key), '-c', cwd,
|
|
505
|
+
...claudeCommand(['--resume', s.claude_session_id, ...profileArgs(profile)]),
|
|
506
|
+
]);
|
|
507
|
+
if (!r.ok)
|
|
508
|
+
throw new SessionError(500, 'CONTROL_FAILED', r.stderr.trim());
|
|
509
|
+
log(`Sessions: resumed ${key}`);
|
|
510
|
+
const attention = await confirmIfNeeded(key, profile);
|
|
511
|
+
return attention ? { ok: true, action, needs_attention: attention } : { ok: true, action };
|
|
512
|
+
}
|
|
513
|
+
//# sourceMappingURL=sessions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessions.js","sourceRoot":"","sources":["../../src/pty/sessions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/** Prefix for sessions the daemon spawned. Anything else is adopted, never owned. */
|
|
2
|
+
export declare const SPAWNED_PREFIX = "dcb-";
|
|
3
|
+
export declare function resolveTmux(): string;
|
|
4
|
+
/** Test seam: forget the cached binary path. */
|
|
5
|
+
export declare function _resetTmuxPath(p?: string | null): void;
|
|
6
|
+
/**
|
|
7
|
+
* Two tmux servers are involved, and they are never mixed:
|
|
8
|
+
*
|
|
9
|
+
* owned `-L decibel` — the daemon's own server. Every spawned session lives
|
|
10
|
+
* here. The daemon starts it, so it starts with the daemon's scrubbed
|
|
11
|
+
* environment (see cleanEnv), and HQ-spawned sessions never appear in,
|
|
12
|
+
* or collide with, the user's own tmux.
|
|
13
|
+
* user the default socket — the user's tmux. Only ever read, attached to
|
|
14
|
+
* and interrupted (adopt); never spawned into or killed.
|
|
15
|
+
*
|
|
16
|
+
* DECIBEL_TMUX_SOCKET / DECIBEL_TMUX_USER_SOCKET rename them, which is how the
|
|
17
|
+
* tests run against private servers instead of real ones.
|
|
18
|
+
*/
|
|
19
|
+
export type TmuxServer = 'owned' | 'user';
|
|
20
|
+
export declare const OWNED_SOCKET_DEFAULT = "decibel";
|
|
21
|
+
export declare function socketArgs(server: TmuxServer): string[];
|
|
22
|
+
/** Which server a session key lives on: the prefix is the ownership mark. */
|
|
23
|
+
/**
|
|
24
|
+
* Terminal title for clients of the owned server (set-titles): the repo, plus
|
|
25
|
+
* the issue label, or else a branch other than main/master. Built from the
|
|
26
|
+
* @dcb_* options the daemon sets at spawn, which cleanLabel has already
|
|
27
|
+
* stripped of control characters. tmux sends it as OSC 2 to every attached
|
|
28
|
+
* client, so a Ghostty tab is titled without any title text in its command
|
|
29
|
+
* (ISS-0210).
|
|
30
|
+
*/
|
|
31
|
+
export declare const TITLE_FORMAT: string;
|
|
32
|
+
export declare function serverFor(name: string): TmuxServer;
|
|
33
|
+
export declare function isDaemonOnlyVar(name: string): boolean;
|
|
34
|
+
/** Names in `base` that cleanEnv drops for being the daemon's. Names only, never values. */
|
|
35
|
+
export declare function daemonOnlyNames(base?: NodeJS.ProcessEnv): string[];
|
|
36
|
+
export declare function cleanEnv(base?: NodeJS.ProcessEnv): Record<string, string>;
|
|
37
|
+
/**
|
|
38
|
+
* tmux keeps the environment its server started with as the GLOBAL
|
|
39
|
+
* environment and copies it into every new session. A server started before
|
|
40
|
+
* ISS-0225 already holds the daemon's variables, so cleaning the client env
|
|
41
|
+
* is not enough: unset them there too. Applied before every spawn and at
|
|
42
|
+
* daemon start.
|
|
43
|
+
*/
|
|
44
|
+
export declare function unsetDaemonEnvArgs(base?: NodeJS.ProcessEnv): string[];
|
|
45
|
+
export interface TmuxResult {
|
|
46
|
+
ok: boolean;
|
|
47
|
+
stdout: string;
|
|
48
|
+
stderr: string;
|
|
49
|
+
}
|
|
50
|
+
export declare function tmux(server: TmuxServer, args: string[], timeoutMs?: number): Promise<TmuxResult>;
|
|
51
|
+
/**
|
|
52
|
+
* Exact-match session target, for commands that take a SESSION target:
|
|
53
|
+
* has-session, kill-session, attach-session.
|
|
54
|
+
*/
|
|
55
|
+
export declare function sessionTarget(name: string): string;
|
|
56
|
+
/**
|
|
57
|
+
* Exact-match target for everything that parses -t as a pane or window:
|
|
58
|
+
* set-option, show-options, send-keys, respawn-pane. tmux 3.5a rejects a bare
|
|
59
|
+
* `=name` there with "no such session"; the trailing colon is required
|
|
60
|
+
* (verified 2026-09-25, and hit independently by decibel-hq's mock).
|
|
61
|
+
*/
|
|
62
|
+
export declare function paneTarget(name: string): string;
|
|
63
|
+
/**
|
|
64
|
+
* Field separator for -F output. PRINTABLE on purpose: with no LANG/LC_* in
|
|
65
|
+
* the environment — which is exactly the launchd daemon's environment — tmux
|
|
66
|
+
* rewrites a TAB in format output as '_', every field collapsed into the
|
|
67
|
+
* session name, and no spawned session ever matched its project. The tests
|
|
68
|
+
* passed because the shell running them had a locale. Pinned by a test that
|
|
69
|
+
* lists with the locale removed.
|
|
70
|
+
*/
|
|
71
|
+
export declare const FIELD_SEP = "|:dcb:|";
|
|
72
|
+
/**
|
|
73
|
+
* Newlines and the field separator would corrupt list output, and a label has
|
|
74
|
+
* no business being long. Applied to every value written into a tmux option.
|
|
75
|
+
*/
|
|
76
|
+
export declare function cleanLabel(v: string | undefined, max?: number): string | undefined;
|
|
77
|
+
export interface TmuxSession {
|
|
78
|
+
name: string;
|
|
79
|
+
project_id?: string;
|
|
80
|
+
branch?: string;
|
|
81
|
+
issue_label?: string;
|
|
82
|
+
claude_session_id?: string;
|
|
83
|
+
created?: string;
|
|
84
|
+
cwd?: string;
|
|
85
|
+
/** The active pane's process has exited (remain-on-exit keeps the session). */
|
|
86
|
+
dead: boolean;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* "No server" is a normal answer; "could not ask" is not. A missing socket
|
|
90
|
+
* means no server, so no sessions. Any other failure — a server that exists
|
|
91
|
+
* but did not answer — must NOT read as an empty list, because HQ would render
|
|
92
|
+
* a live session as gone. It gets one retry and then throws. (A spawned session
|
|
93
|
+
* once went unlisted for minutes while its server was plainly up; the old check
|
|
94
|
+
* swallowed every "error connecting to" as "no server". Cause unverified.)
|
|
95
|
+
*/
|
|
96
|
+
export declare function isNoServer(stderr: string): boolean;
|
|
97
|
+
/** Every session on one server. Empty when that server is not running; throws when it cannot be read. */
|
|
98
|
+
export declare function listSessions(server: TmuxServer): Promise<TmuxSession[]>;
|
|
99
|
+
export declare function parseSessions(stdout: string): TmuxSession[];
|
|
100
|
+
/**
|
|
101
|
+
* pane tty (without /dev/) → session name, across BOTH servers, for matching
|
|
102
|
+
* claude-peers ttys. A user-server session carrying the dcb- prefix is skipped:
|
|
103
|
+
* the prefix means "owned", and honouring it on the wrong server would route
|
|
104
|
+
* attach and kill to a session the daemon does not own.
|
|
105
|
+
*/
|
|
106
|
+
export declare function paneTtyMap(): Promise<Map<string, string>>;
|
|
107
|
+
/** Find a session by key on the server its key says it lives on. */
|
|
108
|
+
export declare function findSession(name: string): Promise<TmuxSession | undefined>;
|
|
109
|
+
//# sourceMappingURL=tmux.d.ts.map
|