@berthdev/berth 0.3.6 → 0.4.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.
Files changed (136) hide show
  1. package/README.md +7 -1
  2. package/dist/src/agents/capabilities.d.ts +13 -0
  3. package/dist/src/agents/capabilities.js +52 -0
  4. package/dist/src/agents/capabilities.js.map +1 -0
  5. package/dist/src/agents/codex-binding.d.ts +10 -0
  6. package/dist/src/agents/codex-binding.js +105 -0
  7. package/dist/src/agents/codex-binding.js.map +1 -0
  8. package/dist/src/agents/commands.d.ts +4 -2
  9. package/dist/src/agents/commands.js +41 -9
  10. package/dist/src/agents/commands.js.map +1 -1
  11. package/dist/src/agents/copilot-state.d.ts +3 -0
  12. package/dist/src/agents/copilot-state.js +94 -0
  13. package/dist/src/agents/copilot-state.js.map +1 -0
  14. package/dist/src/agents/gemini-state.d.ts +3 -0
  15. package/dist/src/agents/gemini-state.js +41 -0
  16. package/dist/src/agents/gemini-state.js.map +1 -0
  17. package/dist/src/agents/hook-files.d.ts +1 -3
  18. package/dist/src/agents/hook-files.js +69 -53
  19. package/dist/src/agents/hook-files.js.map +1 -1
  20. package/dist/src/agents/hook-health.d.ts +4 -0
  21. package/dist/src/agents/hook-health.js +95 -0
  22. package/dist/src/agents/hook-health.js.map +1 -0
  23. package/dist/src/agents/hooks.d.ts +4 -1
  24. package/dist/src/agents/hooks.js +153 -21
  25. package/dist/src/agents/hooks.js.map +1 -1
  26. package/dist/src/agents/jsonl-titles.d.ts +8 -0
  27. package/dist/src/agents/jsonl-titles.js +124 -0
  28. package/dist/src/agents/jsonl-titles.js.map +1 -0
  29. package/dist/src/agents/late-binding.d.ts +2 -0
  30. package/dist/src/agents/late-binding.js +25 -0
  31. package/dist/src/agents/late-binding.js.map +1 -0
  32. package/dist/src/agents/profile.d.ts +14 -0
  33. package/dist/src/agents/profile.js +75 -0
  34. package/dist/src/agents/profile.js.map +1 -0
  35. package/dist/src/agents/registry.d.ts +12 -3
  36. package/dist/src/agents/registry.js +52 -19
  37. package/dist/src/agents/registry.js.map +1 -1
  38. package/dist/src/agents/roots.d.ts +2 -0
  39. package/dist/src/agents/roots.js +21 -0
  40. package/dist/src/agents/roots.js.map +1 -0
  41. package/dist/src/agents/titles.d.ts +14 -0
  42. package/dist/src/agents/titles.js +82 -0
  43. package/dist/src/agents/titles.js.map +1 -0
  44. package/dist/src/agents/transcript-cursor.d.ts +9 -0
  45. package/dist/src/agents/transcript-cursor.js +86 -0
  46. package/dist/src/agents/transcript-cursor.js.map +1 -0
  47. package/dist/src/cli/main.js +40 -7
  48. package/dist/src/cli/main.js.map +1 -1
  49. package/dist/src/config/index.d.ts +6 -0
  50. package/dist/src/config/index.js +37 -6
  51. package/dist/src/config/index.js.map +1 -1
  52. package/dist/src/config/write.d.ts +2 -0
  53. package/dist/src/config/write.js +41 -0
  54. package/dist/src/config/write.js.map +1 -0
  55. package/dist/src/context.js +1 -1
  56. package/dist/src/context.js.map +1 -1
  57. package/dist/src/index.d.ts +11 -5
  58. package/dist/src/index.js +10 -4
  59. package/dist/src/index.js.map +1 -1
  60. package/dist/src/iterm2/install.d.ts +2 -0
  61. package/dist/src/iterm2/install.js +37 -12
  62. package/dist/src/iterm2/install.js.map +1 -1
  63. package/dist/src/present/attach.js +17 -5
  64. package/dist/src/present/attach.js.map +1 -1
  65. package/dist/src/present/state.d.ts +3 -0
  66. package/dist/src/present/state.js +12 -8
  67. package/dist/src/present/state.js.map +1 -1
  68. package/dist/src/process-arguments.d.ts +2 -0
  69. package/dist/src/process-arguments.js +59 -0
  70. package/dist/src/process-arguments.js.map +1 -0
  71. package/dist/src/process-directory.d.ts +2 -0
  72. package/dist/src/process-directory.js +37 -0
  73. package/dist/src/process-directory.js.map +1 -0
  74. package/dist/src/process-owner.d.ts +7 -0
  75. package/dist/src/process-owner.js +51 -0
  76. package/dist/src/process-owner.js.map +1 -0
  77. package/dist/src/registry/directory.d.ts +2 -0
  78. package/dist/src/registry/directory.js +19 -0
  79. package/dist/src/registry/directory.js.map +1 -0
  80. package/dist/src/registry/discover.d.ts +15 -5
  81. package/dist/src/registry/discover.js +135 -38
  82. package/dist/src/registry/discover.js.map +1 -1
  83. package/dist/src/registry/doctor.d.ts +5 -1
  84. package/dist/src/registry/doctor.js +53 -12
  85. package/dist/src/registry/doctor.js.map +1 -1
  86. package/dist/src/registry/hosts.d.ts +28 -0
  87. package/dist/src/registry/hosts.js +73 -0
  88. package/dist/src/registry/hosts.js.map +1 -0
  89. package/dist/src/registry/launch.d.ts +3 -0
  90. package/dist/src/registry/launch.js +29 -0
  91. package/dist/src/registry/launch.js.map +1 -0
  92. package/dist/src/registry/native-state.d.ts +20 -0
  93. package/dist/src/registry/native-state.js +127 -0
  94. package/dist/src/registry/native-state.js.map +1 -0
  95. package/dist/src/registry/sessions.d.ts +21 -3
  96. package/dist/src/registry/sessions.js +178 -37
  97. package/dist/src/registry/sessions.js.map +1 -1
  98. package/dist/src/restore/ensure.d.ts +12 -2
  99. package/dist/src/restore/ensure.js +171 -37
  100. package/dist/src/restore/ensure.js.map +1 -1
  101. package/dist/src/restore/lock.d.ts +3 -5
  102. package/dist/src/restore/lock.js +82 -52
  103. package/dist/src/restore/lock.js.map +1 -1
  104. package/dist/src/restore/status.d.ts +9 -0
  105. package/dist/src/restore/status.js +16 -0
  106. package/dist/src/restore/status.js.map +1 -0
  107. package/dist/src/snapshot/identity.d.ts +7 -0
  108. package/dist/src/snapshot/identity.js +20 -0
  109. package/dist/src/snapshot/identity.js.map +1 -0
  110. package/dist/src/snapshot/lifecycle.d.ts +9 -0
  111. package/dist/src/snapshot/lifecycle.js +37 -0
  112. package/dist/src/snapshot/lifecycle.js.map +1 -0
  113. package/dist/src/snapshot/store.d.ts +11 -1
  114. package/dist/src/snapshot/store.js +28 -9
  115. package/dist/src/snapshot/store.js.map +1 -1
  116. package/dist/src/snapshot/take.d.ts +2 -1
  117. package/dist/src/snapshot/take.js +29 -25
  118. package/dist/src/snapshot/take.js.map +1 -1
  119. package/dist/src/tmux/client.d.ts +6 -2
  120. package/dist/src/tmux/client.js +49 -25
  121. package/dist/src/tmux/client.js.map +1 -1
  122. package/dist/src/tmux/connections.d.ts +22 -0
  123. package/dist/src/tmux/connections.js +70 -0
  124. package/dist/src/tmux/connections.js.map +1 -0
  125. package/dist/src/tmux/fields.d.ts +7 -0
  126. package/dist/src/tmux/fields.js +23 -0
  127. package/dist/src/tmux/fields.js.map +1 -0
  128. package/dist/src/tmux/install.js +31 -18
  129. package/dist/src/tmux/install.js.map +1 -1
  130. package/dist/src/tools.d.ts +3 -1
  131. package/dist/src/tools.js +23 -11
  132. package/dist/src/tools.js.map +1 -1
  133. package/package.json +1 -1
  134. package/dist/src/agents/name-key.d.ts +0 -1
  135. package/dist/src/agents/name-key.js +0 -66
  136. package/dist/src/agents/name-key.js.map +0 -1
@@ -21,8 +21,14 @@ export class SnapshotStore {
21
21
  return [];
22
22
  return readdirSync(this.root)
23
23
  .filter((name) => DIR_PATTERN.test(name) && existsSync(join(this.root, name, 'sessions.json')))
24
- .sort()
25
- .reverse()
24
+ .sort((a, b) => {
25
+ const parse = (value) => {
26
+ const parts = /^(\d{8}T\d{6})(\d{3})?Z(?:-(\d+))?$/.exec(value);
27
+ return { time: parts[1] + (parts[2] ?? '000'), sequence: Number(parts[3] ?? 1) };
28
+ };
29
+ const x = parse(a), y = parse(b);
30
+ return y.time.localeCompare(x.time) || y.sequence - x.sequence;
31
+ })
26
32
  .map((name) => join(this.root, name));
27
33
  }
28
34
  read(dir) {
@@ -49,12 +55,14 @@ export class SnapshotStore {
49
55
  /** Write atomically: build in a temporary directory, then rename into place. */
50
56
  write(sessions, scrollback, now = new Date()) {
51
57
  mkdirSync(this.root, { recursive: true });
52
- let name = timestampDir(now);
58
+ const latest = this.newest();
59
+ const committedAt = latest && Date.parse(latest.createdAt) > now.getTime() ? new Date(latest.createdAt) : now;
60
+ let name = timestampDir(committedAt);
53
61
  for (let n = 2; existsSync(join(this.root, name)); n++)
54
- name = `${timestampDir(now)}-${n}`;
62
+ name = `${timestampDir(committedAt)}-${n}`;
55
63
  const tmp = join(this.root, `.tmp-${process.pid}-${name}`);
56
64
  mkdirSync(join(tmp, 'scrollback'), { recursive: true });
57
- const snapshot = { version: SNAPSHOT_VERSION, createdAt: now.toISOString(), sessions };
65
+ const snapshot = { version: SNAPSHOT_VERSION, createdAt: committedAt.toISOString(), sessions };
58
66
  writeFileSync(join(tmp, 'sessions.json'), `${JSON.stringify(snapshot, null, 2)}\n`);
59
67
  for (const [session, text] of Object.entries(scrollback)) {
60
68
  writeFileSync(join(tmp, 'scrollback', scrollbackFile(session)), text);
@@ -72,7 +80,7 @@ export class SnapshotStore {
72
80
  rmSync(tmp, { recursive: true, force: true });
73
81
  throw error;
74
82
  }
75
- name = `${timestampDir(now)}-${n}`;
83
+ name = `${timestampDir(committedAt)}-${n}`;
76
84
  }
77
85
  }
78
86
  }
@@ -80,11 +88,22 @@ export class SnapshotStore {
80
88
  for (const dir of this.list().slice(keep))
81
89
  rmSync(dir, { recursive: true, force: true });
82
90
  }
91
+ /** Missing output is optional; unreadable output must not be silently discarded. */
92
+ optionalScrollback(dir, session) {
93
+ try {
94
+ return readFileSync(join(dir, 'scrollback', scrollbackFile(session)), 'utf8');
95
+ }
96
+ catch (error) {
97
+ if (error.code === 'ENOENT')
98
+ return undefined;
99
+ throw error;
100
+ }
101
+ }
83
102
  scrollback(dir, session) {
84
- const file = join(dir, 'scrollback', scrollbackFile(session));
85
- if (!existsSync(file))
103
+ const text = this.optionalScrollback(dir, session);
104
+ if (text === undefined)
86
105
  throw new BerthError(`no saved scrollback for ${session}`, ExitCode.notFound);
87
- return readFileSync(file, 'utf8');
106
+ return text;
88
107
  }
89
108
  }
90
109
  //# sourceMappingURL=store.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/snapshot/store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/snapshot/store.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import type { Context } from '../context.js';
2
+ import type { SnapshotSession } from './store.js';
2
3
  /** Snapshot, never throwing: for callers whose own work must not fail on it. */
3
4
  export declare function snapshotQuietly(ctx: Context): void;
4
5
  /** Manage sessions found running an agent, and snapshot when there were any. */
@@ -10,4 +11,4 @@ export declare function adoptDiscovered(ctx: Context): string[];
10
11
  * forgotten. A session missing from the same server ended on purpose (exit,
11
12
  * kill) and is dropped. Returns the snapshot directory.
12
13
  */
13
- export declare function takeSnapshot(ctx: Context, now?: Date, forget?: readonly string[]): string;
14
+ export declare function takeSnapshot(ctx: Context, now?: Date, forget?: readonly string[], pending?: readonly SnapshotSession[]): string;
@@ -1,4 +1,8 @@
1
- import { conversationByName } from '../agents/name-key.js';
1
+ import { readProfile } from '../agents/profile.js';
2
+ import { nameCollision } from './identity.js';
3
+ import { watchClosures, wasClosed } from './lifecycle.js';
4
+ import { recoveryStatus } from '../restore/status.js';
5
+ import { withLock } from '../restore/lock.js';
2
6
  import { discover } from '../registry/discover.js';
3
7
  /** Snapshot, never throwing: for callers whose own work must not fail on it. */
4
8
  export function snapshotQuietly(ctx) {
@@ -23,42 +27,42 @@ export function adoptDiscovered(ctx) {
23
27
  * forgotten. A session missing from the same server ended on purpose (exit,
24
28
  * kill) and is dropped. Returns the snapshot directory.
25
29
  */
26
- export function takeSnapshot(ctx, now = new Date(), forget = []) {
30
+ export function takeSnapshot(ctx, now, forget = [], pending = []) {
31
+ return withLock(ctx.config.stateDir, () => collectSnapshot(ctx, now ?? new Date(), forget, pending));
32
+ }
33
+ function collectSnapshot(ctx, now, forget, pending) {
27
34
  const sessions = [];
28
- const scrollback = {};
35
+ watchClosures(ctx);
29
36
  discover(ctx);
30
37
  const live = ctx.tmux.listSessions();
31
38
  const serverStart = live[0]?.serverStart;
39
+ const previous = ctx.store.newest();
40
+ const collisions = new Set(live.filter((session) => nameCollision(ctx, session, previous?.sessions ?? [])).map((session) => session.name));
32
41
  for (const s of live) {
33
- if (!s.meta.agent)
42
+ if (!s.meta.agent || collisions.has(s.name))
34
43
  continue;
35
44
  const cwd = s.meta.cwd ?? s.path;
36
- let conversation = s.meta.conversation ?? '';
37
- // No hook-reported id: fall back to the name key (spec §4.2).
38
- if (!conversation) {
39
- conversation = conversationByName(s.meta.agent, cwd, s.name) ?? '';
40
- if (conversation)
41
- ctx.tmux.setMeta(s.name, { conversation });
42
- }
43
- sessions.push({ name: s.name, cwd, agent: s.meta.agent, argv: s.meta.argv ?? '', conversation, origin: s.meta.origin ?? 'none', serverStart: s.serverStart });
44
- scrollback[s.name] = ctx.tmux.capturePane(s.name, ctx.config.scrollbackLines);
45
+ const conversation = s.meta.conversation ?? '';
46
+ sessions.push({ profile: readProfile(s.meta.agent, s.meta.profile), ...recoveryStatus(ctx.tmux, s.name, s.meta), ...(s.meta.ownerWorkspace ? { ownerWorkspace: s.meta.ownerWorkspace } : {}), name: s.name, cwd, agent: s.meta.agent, argv: s.meta.argv ?? '', argvVerified: s.meta.argvVerified === '1', conversation, origin: s.meta.origin ?? 'none', serverStart: s.serverStart, sessionId: s.sessionId, ...(s.meta.bindingIssue ? { bindingIssue: s.meta.bindingIssue } : {}) });
45
47
  }
46
- const liveNames = new Set(live.map((s) => s.name));
47
- const previous = ctx.store.newest();
48
- for (const old of previous?.sessions ?? []) {
49
- if (liveNames.has(old.name) || forget.includes(old.name))
48
+ const liveNames = new Set(live.filter((s) => !collisions.has(s.name)).map((s) => s.name));
49
+ const pendingNames = new Set(pending.map((session) => session.name));
50
+ const records = [...pending, ...(previous?.sessions ?? []).filter((session) => !pendingNames.has(session.name))];
51
+ for (const old of records) {
52
+ if (liveNames.has(old.name) || forget.includes(old.name) || (!pendingNames.has(old.name) && wasClosed(ctx, old)))
50
53
  continue;
51
54
  // Older snapshots do not say which server they saw: keep the old behaviour.
52
- if (!old.serverStart || old.serverStart === serverStart)
55
+ if (!pendingNames.has(old.name) && !collisions.has(old.name) && !old.retained && old.recovery !== 'failed' && (!old.serverStart || old.serverStart === serverStart))
53
56
  continue;
54
- sessions.push(old);
55
- try {
56
- scrollback[old.name] = ctx.store.scrollback(previous.dir, old.name);
57
- }
58
- catch {
59
- // No saved scrollback; the session still comes back.
60
- }
57
+ sessions.push(collisions.has(old.name) || pendingNames.has(old.name) ? { ...old, retained: true } : old);
61
58
  }
59
+ const scrollback = Object.fromEntries(sessions.flatMap((session) => {
60
+ if (liveNames.has(session.name)) {
61
+ return [[session.name, ctx.tmux.capturePane(session.name, ctx.config.scrollbackLines)]];
62
+ }
63
+ const text = previous ? ctx.store.optionalScrollback(previous.dir, session.name) : undefined;
64
+ return text === undefined ? [] : [[session.name, text]];
65
+ }));
62
66
  const dir = ctx.store.write(sessions, scrollback, now);
63
67
  ctx.store.prune(ctx.config.retention);
64
68
  return dir;
@@ -1 +1 @@
1
- {"version":3,"file":"take.js","sourceRoot":"","sources":["../../../src/snapshot/take.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"take.js","sourceRoot":"","sources":["../../../src/snapshot/take.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  /** Berth metadata stored on a tmux session as user options (spec §4). */
2
- export declare const META_KEYS: readonly ["agent", "cwd", "argv", "conversation", "origin", "state", "note"];
2
+ export declare const META_KEYS: readonly ["agent", "cwd", "argv", "argvVerified", "conversation", "origin", "state", "stateRevision", "nativeCheckedAt", "nativeTranscript", "note", "topic", "producerPane", "producerLifetime", "bindingIssue", "recovery", "recoveryAt", "recoveryDetail", "ownerWorkspace", "restoreSource", "profile"];
3
3
  export type MetaKey = (typeof META_KEYS)[number];
4
4
  export type SessionMeta = Partial<Record<MetaKey, string>>;
5
5
  export interface LiveSession {
@@ -9,8 +9,10 @@ export interface LiveSession {
9
9
  meta: SessionMeta;
10
10
  /** The tmux server's start time and pid: names one server lifetime. */
11
11
  serverStart: string;
12
+ sessionId: string;
12
13
  }
13
14
  export interface TmuxTarget {
15
+ env?: Record<string, string | undefined>;
14
16
  bin: string;
15
17
  /** `-L` socket name; undefined addresses the default server (or $TMUX inside a pane). */
16
18
  socket?: string;
@@ -34,7 +36,9 @@ export declare class Tmux {
34
36
  /** Working directory of the session's active pane, as the shell or agent left it. */
35
37
  paneCurrentPath(name: string): string | undefined;
36
38
  hasSession(name: string): boolean;
37
- newSession(name: string, cwd: string, command: string): void;
39
+ newSession(name: string, cwd: string, command: string): string;
40
+ /** Explicit values/removals override a server's older global environment. */
41
+ setEnvironment(name: string, values: Record<string, string | undefined>): void;
38
42
  setMeta(name: string, meta: SessionMeta): void;
39
43
  /**
40
44
  * Make tmux send the session's name, prefixed by its agent state, as the
@@ -1,8 +1,10 @@
1
+ import { formatFields, readFields } from './fields.js';
2
+ import { randomUUID } from 'node:crypto';
3
+ import { basename } from 'node:path';
1
4
  import { spawnSync } from 'node:child_process';
2
5
  import { BerthError, ExitCode } from '../errors.js';
3
6
  /** Berth metadata stored on a tmux session as user options (spec §4). */
4
- export const META_KEYS = ['agent', 'cwd', 'argv', 'conversation', 'origin', 'state', 'note'];
5
- const SEP = '\x1f';
7
+ export const META_KEYS = ['agent', 'cwd', 'argv', 'argvVerified', 'conversation', 'origin', 'state', 'stateRevision', 'nativeCheckedAt', 'nativeTranscript', 'note', 'topic', 'producerPane', 'producerLifetime', 'bindingIssue', 'recovery', 'recoveryAt', 'recoveryDetail', 'ownerWorkspace', 'restoreSource', 'profile'];
6
8
  const TEST_SOCKET_PREFIX = 'berth-test-';
7
9
  export class Tmux {
8
10
  target;
@@ -19,7 +21,7 @@ export class Tmux {
19
21
  }
20
22
  /** Run tmux; returns stdout. Throws BerthError on failure unless `allowFail`. */
21
23
  run(args, allowFail = false) {
22
- const result = spawnSync(this.target.bin, [...this.baseArgs(), ...args], { encoding: 'utf8' });
24
+ const result = spawnSync(this.target.bin, [...this.baseArgs(), ...args], { env: this.target.env, encoding: 'utf8', timeout: 3000, killSignal: 'SIGKILL', maxBuffer: 8 * 1024 * 1024 });
23
25
  if (result.error) {
24
26
  throw new BerthError(`tmux unavailable (${this.target.bin}): ${result.error.message}`, ExitCode.tmuxUnavailable);
25
27
  }
@@ -33,48 +35,69 @@ export class Tmux {
33
35
  return this.run(['list-sessions', '-F', '#{session_name}'], true).ok;
34
36
  }
35
37
  listSessions() {
36
- const fields = ['#{session_name}', '#{session_attached}', '#{session_path}', '#{start_time}-#{pid}', ...META_KEYS.map((k) => `#{@berth_${k}}`)];
37
- const result = this.run(['list-sessions', '-F', fields.join(SEP)], true);
38
- if (!result.ok)
39
- return [];
40
- return result.stdout
41
- .split('\n')
42
- .filter((line) => line.length > 0)
43
- .map((line) => {
44
- const [name, attached, path, serverStart, ...values] = line.split(SEP);
38
+ const fields = ['session_name', 'session_attached', '?session_path,#{session_path},#{pane_current_path}', 'start_time', 'pid', 'session_id', ...META_KEYS.map((k) => `@berth_${k}`)];
39
+ const result = this.run(['list-sessions', '-F', formatFields(fields)], true);
40
+ if (!result.ok) {
41
+ if (/no server running|No such file or directory|Connection refused/i.test(result.stderr))
42
+ return [];
43
+ throw new BerthError(`Cannot read tmux sessions: ${result.stderr.trim()}`, ExitCode.failure);
44
+ }
45
+ return readFields(result.stdout, fields.length).map((fields) => {
46
+ const [name, attached, path, start, pid, sessionId, ...values] = fields;
47
+ const serverStart = `${start}-${pid}`;
45
48
  const meta = {};
46
49
  META_KEYS.forEach((key, i) => {
47
- if (values[i])
48
- meta[key] = values[i];
50
+ if (values[i]) {
51
+ const value = values[i];
52
+ if (key === 'argv' && value.startsWith('berth-json:')) {
53
+ const decoded = JSON.parse(value.slice('berth-json:'.length));
54
+ if (typeof decoded !== 'string')
55
+ throw new BerthError('Invalid encoded launch arguments.');
56
+ meta[key] = decoded;
57
+ }
58
+ else
59
+ meta[key] = value;
60
+ }
49
61
  });
50
- return { name, attachedClients: Number(attached) || 0, path, meta, serverStart };
62
+ return { name, attachedClients: Number(attached) || 0, path, meta, serverStart, sessionId };
51
63
  });
52
64
  }
53
65
  /** Session that owns a pane, e.g. $TMUX_PANE inside an agent's hook. */
54
66
  sessionOfPane(pane) {
55
- const result = this.run(['display-message', '-p', '-t', pane, '#{session_name}'], true);
56
- const name = result.stdout.trim();
67
+ const result = this.run(['display-message', '-p', '-t', pane, formatFields(['session_name'])], true);
68
+ const name = result.ok ? readFields(result.stdout, 1)[0]?.[0] : undefined;
57
69
  return result.ok && name ? name : undefined;
58
70
  }
59
71
  /** Working directory of the session's active pane, as the shell or agent left it. */
60
72
  paneCurrentPath(name) {
61
- const result = this.run(['display-message', '-p', '-t', `=${name}:`, '#{pane_current_path}'], true);
62
- const path = result.stdout.trim();
73
+ const result = this.run(['display-message', '-p', '-t', `=${name}:`, formatFields(['pane_current_path'])], true);
74
+ const path = result.ok ? readFields(result.stdout, 1)[0]?.[0] : undefined;
63
75
  return result.ok && path ? path : undefined;
64
76
  }
65
77
  hasSession(name) {
66
78
  return this.run(['has-session', '-t', `=${name}`], true).ok;
67
79
  }
68
80
  newSession(name, cwd, command) {
69
- const args = ['new-session', '-d', '-s', name, '-c', cwd];
70
- this.run(command ? [...args, command] : args);
81
+ const args = ['new-session', '-d', '-P', '-F', '#{session_id}', '-s', name, '-c', cwd];
82
+ return this.run(command ? [...args, command] : args).stdout.trim();
83
+ }
84
+ /** Explicit values/removals override a server's older global environment. */
85
+ setEnvironment(name, values) {
86
+ for (const [key, value] of Object.entries(values)) {
87
+ this.run(value === undefined
88
+ ? ['set-environment', '-r', '-t', `=${name}:`, key]
89
+ : ['set-environment', '-t', `=${name}:`, key, value]);
90
+ }
71
91
  }
72
92
  setMeta(name, meta) {
73
- for (const [key, value] of Object.entries(meta)) {
93
+ const values = meta.state === undefined ? meta : { ...meta, stateRevision: randomUUID() };
94
+ for (const [key, value] of Object.entries(values)) {
74
95
  if (value === undefined)
75
96
  continue;
76
- // One line per session in list output: no newlines or separators in values.
77
- this.run(['set-option', '-t', `=${name}:`, `@berth_${key}`, value.replace(/[\r\n\x1f]+/g, ' ')]);
97
+ // Argument values must survive the line-delimited tmux transport unchanged.
98
+ const encoded = key === 'argv' && (/[\r\n\x1f]/.test(value) || value.startsWith('berth-json:'))
99
+ ? `berth-json:${JSON.stringify(value)}` : value;
100
+ this.run(['set-option', '-t', `=${name}:`, `@berth_${key}`, encoded]);
78
101
  }
79
102
  }
80
103
  /**
@@ -102,7 +125,8 @@ export class Tmux {
102
125
  }
103
126
  /** Server-wide kill, allowed only on Berth test sockets (implementation §5.1). */
104
127
  killServer() {
105
- if (!this.target.socket?.startsWith(TEST_SOCKET_PREFIX)) {
128
+ const endpoint = this.target.socketPath ? basename(this.target.socketPath) : this.target.socket;
129
+ if (!endpoint?.startsWith(TEST_SOCKET_PREFIX)) {
106
130
  throw new BerthError('refusing to kill a tmux server that is not a Berth test server');
107
131
  }
108
132
  this.run(['kill-server'], true);
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/tmux/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/tmux/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { HostRecord } from '../registry/hosts.js';
2
+ import type { Tmux } from './client.js';
3
+ export interface ConnectionInfo {
4
+ pid: number;
5
+ terminal: string;
6
+ application: string;
7
+ workspace?: string;
8
+ ancestors: number[];
9
+ }
10
+ export declare function processAncestry(pid: number, table: string): {
11
+ ancestors: number[];
12
+ application: string;
13
+ };
14
+ /** Live clients only; restore ownership is deliberately not consulted. */
15
+ export declare function connections(tmux: Tmux, hosts?: readonly HostRecord[]): ReadonlyMap<string, ConnectionInfo[]>;
16
+ /** Wait for this terminal process to attach to this exact session, not any client. */
17
+ export declare function waitForAttachment(tmux: Tmux, session: string, terminalPid: number, options?: {
18
+ timeoutMs?: number;
19
+ exited?: () => boolean;
20
+ }): Promise<void>;
21
+ /** Detach only clients proven to belong to the caller's terminal processes. */
22
+ export declare function detachTerminalClients(tmux: Tmux, session: string, terminalPids: ReadonlySet<number>): void;
@@ -0,0 +1,70 @@
1
+ import { formatFields, readFields } from './fields.js';
2
+ import { spawnSync } from 'node:child_process';
3
+ export function processAncestry(pid, table) {
4
+ const processes = new Map(table.split('\n').flatMap((line) => {
5
+ const match = /^\s*(\d+)\s+(\d+)\s+(.+)$/.exec(line);
6
+ return match ? [[Number(match[1]), { parent: Number(match[2]), command: match[3] }]] : [];
7
+ }));
8
+ const ancestors = [];
9
+ let application = '';
10
+ for (let current = pid; current > 1 && ancestors.length < 64 && !ancestors.includes(current);) {
11
+ ancestors.push(current);
12
+ const process = processes.get(current);
13
+ if (!process)
14
+ break;
15
+ if (/iTerm/i.test(process.command))
16
+ application ||= 'iTerm2';
17
+ else if (/Cursor(?:\.app| Helper)/i.test(process.command))
18
+ application ||= 'Cursor';
19
+ else if (/Visual Studio Code|Code Helper|\/code(?:\s|$)/i.test(process.command))
20
+ application ||= 'VS Code';
21
+ else if (/Terminal\.app/.test(process.command))
22
+ application ||= 'Terminal';
23
+ else if (/WezTerm|wezterm/.test(process.command))
24
+ application ||= 'WezTerm';
25
+ else if (/ghostty/i.test(process.command))
26
+ application ||= 'Ghostty';
27
+ current = process.parent;
28
+ }
29
+ return { ancestors, application };
30
+ }
31
+ /** Live clients only; restore ownership is deliberately not consulted. */
32
+ export function connections(tmux, hosts = []) {
33
+ const result = tmux.run(['list-clients', '-F', formatFields(['client_session', 'client_pid', 'client_tty', 'client_termtype'])], true);
34
+ if (!result.ok || !result.stdout.trim())
35
+ return new Map();
36
+ const processes = spawnSync('ps', ['-axo', 'pid=,ppid=,comm='], { encoding: 'utf8', timeout: 2000, killSignal: 'SIGKILL' });
37
+ const entries = readFields(result.stdout, 4).map(([session, rawPid, terminal, termtype]) => {
38
+ const pid = Number(rawPid);
39
+ const ancestry = processAncestry(pid, processes.status === 0 ? processes.stdout : '');
40
+ const host = hosts.find((host) => host.terminalPids.some((pid) => ancestry.ancestors.includes(pid)));
41
+ const application = typeof host?.application === 'string' ? host.application.trim() : '';
42
+ return { session, client: { pid, terminal, ...ancestry, ...(host?.workspace ? { workspace: host.workspace.label } : {}), application: application || ancestry.application || (/iterm/i.test(termtype) ? 'iTerm2' : '') } };
43
+ }).filter(({ client }) => Number.isSafeInteger(client.pid) && client.pid > 0);
44
+ return new Map([...new Set(entries.map((entry) => entry.session))].map((session) => [session, entries.filter((entry) => entry.session === session).map((entry) => entry.client)]));
45
+ }
46
+ /** Wait for this terminal process to attach to this exact session, not any client. */
47
+ export async function waitForAttachment(tmux, session, terminalPid, options = {}) {
48
+ const deadline = Date.now() + (options.timeoutMs ?? 5000);
49
+ do {
50
+ if (options.exited?.())
51
+ throw new Error(`Terminal exited before attaching to ${session}. Try opening it again.`);
52
+ const clients = connections(tmux).get(session) ?? [];
53
+ if (clients.some((client) => client.ancestors.includes(terminalPid)))
54
+ return;
55
+ if (Date.now() >= deadline)
56
+ break;
57
+ await new Promise((resolve) => setTimeout(resolve, 50));
58
+ } while (true);
59
+ throw new Error(`Could not confirm attachment to ${session}. Check tmux and try opening it again.`);
60
+ }
61
+ /** Detach only clients proven to belong to the caller's terminal processes. */
62
+ export function detachTerminalClients(tmux, session, terminalPids) {
63
+ const clients = connections(tmux).get(session) ?? [];
64
+ for (const client of clients) {
65
+ if (client.terminal && client.ancestors.some((pid) => terminalPids.has(pid))) {
66
+ tmux.run(['detach-client', '-t', client.terminal]);
67
+ }
68
+ }
69
+ }
70
+ //# sourceMappingURL=connections.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connections.js","sourceRoot":"","sources":["../../../src/tmux/connections.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /** Encode before framing. Nested substitutions also work on tmux 3.0,
2
+ * whose chained modifiers retain only the last substitution. */
3
+ export declare function formatFields(keys: readonly string[]): string;
4
+ /** Decode once so escape-looking source text stays literal. */
5
+ export declare function readFields(output: string, count: number): string[][];
6
+ /** Quote literal data embedded in a tmux format, separately from shell quoting. */
7
+ export declare function formatLiteral(value: string): string;
@@ -0,0 +1,23 @@
1
+ import { BerthError } from '../errors.js';
2
+ const SEPARATOR = '~';
3
+ const escapeEntries = ['=', '\n', '\r', '\t', '\x1f', SEPARATOR].map((character) => [character.charCodeAt(0).toString(16).toUpperCase().padStart(2, '0'), character]);
4
+ const escapes = Object.fromEntries(escapeEntries);
5
+ /** Encode before framing. Nested substitutions also work on tmux 3.0,
6
+ * whose chained modifiers retain only the last substitution. */
7
+ export function formatFields(keys) {
8
+ return keys.map((key) => escapeEntries.reduce((inner, [code, character]) => `#{s|${character}|=${code}|:?pid,${inner},}`, `#{${key}}`)).join(SEPARATOR);
9
+ }
10
+ /** Decode once so escape-looking source text stays literal. */
11
+ export function readFields(output, count) {
12
+ return output.split('\n').filter((line) => line.length > 0).map((line) => {
13
+ const fields = line.split(SEPARATOR);
14
+ if (fields.length !== count)
15
+ throw new BerthError('Malformed tmux record; refusing to infer session identity.');
16
+ return fields.map((value) => value.replace(/=([0-9A-F]{2})/g, (match, code) => escapes[code] ?? match));
17
+ });
18
+ }
19
+ /** Quote literal data embedded in a tmux format, separately from shell quoting. */
20
+ export function formatLiteral(value) {
21
+ return value.replaceAll("#", "##");
22
+ }
23
+ //# sourceMappingURL=fields.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fields.js","sourceRoot":"","sources":["../../../src/tmux/fields.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,MAAM,SAAS,GAAG,GAAG,CAAC;AACtB,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CACjF,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,SAAS,CAAU,CAAC,CAAC;AAC7F,MAAM,OAAO,GAAqC,MAAM,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC;AAEpF;gEACgE;AAChE,MAAM,UAAU,YAAY,CAAC,IAAuB;IAClD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,SAAS,CAAC,EAAE,EAAE,CACzE,OAAO,SAAS,KAAK,IAAI,UAAU,KAAK,IAAI,EAAE,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;AAChF,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,UAAU,CAAC,MAAc,EAAE,KAAa;IACtD,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACvE,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACrC,IAAI,MAAM,CAAC,MAAM,KAAK,KAAK;YAAE,MAAM,IAAI,UAAU,CAAC,4DAA4D,CAAC,CAAC;QAChH,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,iBAAiB,EAAE,CAAC,KAAK,EAAE,IAAY,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC;IAClH,CAAC,CAAC,CAAC;AACL,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,OAAO,KAAK,CAAC,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;AACrC,CAAC"}