nterminal 1.3.4 → 1.3.5

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 (113) hide show
  1. package/bin/nterminal.js +8 -3
  2. package/dist/client/assets/MarkdownPreview-BIrwUAaa.js +1 -0
  3. package/dist/client/assets/{TranscriptMarkdownBody-H8ZsISc6.js → TranscriptMarkdownBody-CI0ztvMX.js} +1 -1
  4. package/dist/client/assets/{index-DxfBq-4P.js → index-EN8ngMgv.js} +1 -1
  5. package/dist/client/assets/index-JQJ1Eet1.js +58 -0
  6. package/dist/client/assets/index-xkL4h3qt.css +1 -0
  7. package/dist/client/index.html +2 -2
  8. package/dist/scripts/hooks.js +83 -0
  9. package/dist/scripts/hooks.js.map +1 -0
  10. package/dist/server/accounts/accountService.d.ts +23 -1
  11. package/dist/server/accounts/accountService.js +235 -103
  12. package/dist/server/accounts/accountService.js.map +1 -1
  13. package/dist/server/accounts/providerRequests.d.ts +12 -0
  14. package/dist/server/accounts/providerRequests.js +159 -0
  15. package/dist/server/accounts/providerRequests.js.map +1 -0
  16. package/dist/server/agent/agentRoutes.js +11 -0
  17. package/dist/server/agent/agentRoutes.js.map +1 -1
  18. package/dist/server/hooks/helperJournal.d.ts +16 -0
  19. package/dist/server/hooks/helperJournal.js +74 -0
  20. package/dist/server/hooks/helperJournal.js.map +1 -0
  21. package/dist/server/hooks/hookBinding.d.ts +39 -0
  22. package/dist/server/hooks/hookBinding.js +91 -0
  23. package/dist/server/hooks/hookBinding.js.map +1 -0
  24. package/dist/server/hooks/hookFiles.d.ts +24 -0
  25. package/dist/server/hooks/hookFiles.js +160 -0
  26. package/dist/server/hooks/hookFiles.js.map +1 -0
  27. package/dist/server/hooks/hookInstallation.d.ts +79 -0
  28. package/dist/server/hooks/hookInstallation.js +978 -0
  29. package/dist/server/hooks/hookInstallation.js.map +1 -0
  30. package/dist/server/hooks/hookProcess.d.ts +5 -0
  31. package/dist/server/hooks/hookProcess.js +85 -0
  32. package/dist/server/hooks/hookProcess.js.map +1 -0
  33. package/dist/server/hooks/hookReceiver.d.ts +66 -0
  34. package/dist/server/hooks/hookReceiver.js +549 -0
  35. package/dist/server/hooks/hookReceiver.js.map +1 -0
  36. package/dist/server/hooks/lifecycle.d.ts +40 -0
  37. package/dist/server/hooks/lifecycle.js +200 -0
  38. package/dist/server/hooks/lifecycle.js.map +1 -0
  39. package/dist/server/hooks/publicationLock.d.ts +3 -0
  40. package/dist/server/hooks/publicationLock.js +137 -0
  41. package/dist/server/hooks/publicationLock.js.map +1 -0
  42. package/dist/server/hooks/verifiedLock.d.ts +24 -0
  43. package/dist/server/hooks/verifiedLock.js +207 -0
  44. package/dist/server/hooks/verifiedLock.js.map +1 -0
  45. package/dist/server/http.d.ts +4 -0
  46. package/dist/server/http.js +6 -0
  47. package/dist/server/http.js.map +1 -1
  48. package/dist/server/index.js +69 -2
  49. package/dist/server/index.js.map +1 -1
  50. package/dist/server/notifications/agentCompletionMonitor.d.ts +16 -1
  51. package/dist/server/notifications/agentCompletionMonitor.js +261 -47
  52. package/dist/server/notifications/agentCompletionMonitor.js.map +1 -1
  53. package/dist/server/notifications/completionNotificationRouter.d.ts +2 -0
  54. package/dist/server/notifications/completionNotificationRouter.js +9 -0
  55. package/dist/server/notifications/completionNotificationRouter.js.map +1 -1
  56. package/dist/server/routes/accountRoutes.js +11 -0
  57. package/dist/server/routes/accountRoutes.js.map +1 -1
  58. package/dist/server/routes/activityRoutes.d.ts +13 -0
  59. package/dist/server/routes/activityRoutes.js +165 -0
  60. package/dist/server/routes/activityRoutes.js.map +1 -0
  61. package/dist/server/routes/agentManagementRoutes.js +8 -1
  62. package/dist/server/routes/agentManagementRoutes.js.map +1 -1
  63. package/dist/server/routes/hookRoutes.d.ts +16 -0
  64. package/dist/server/routes/hookRoutes.js +77 -0
  65. package/dist/server/routes/hookRoutes.js.map +1 -0
  66. package/dist/server/routes/terminalRoutes.js +4 -0
  67. package/dist/server/routes/terminalRoutes.js.map +1 -1
  68. package/dist/server/routes/transcriptQuery.d.ts +2 -1
  69. package/dist/server/routes/transcriptQuery.js +3 -1
  70. package/dist/server/routes/transcriptQuery.js.map +1 -1
  71. package/dist/server/terminal/PtyAdapter.d.ts +18 -0
  72. package/dist/server/terminal/PtyAdapter.js.map +1 -1
  73. package/dist/server/terminal/TerminalManager.d.ts +61 -0
  74. package/dist/server/terminal/TerminalManager.js +665 -12
  75. package/dist/server/terminal/TerminalManager.js.map +1 -1
  76. package/dist/server/terminal/TmuxPtyAdapter.d.ts +14 -2
  77. package/dist/server/terminal/TmuxPtyAdapter.js +99 -15
  78. package/dist/server/terminal/TmuxPtyAdapter.js.map +1 -1
  79. package/dist/server/terminal/activityChannel.d.ts +57 -0
  80. package/dist/server/terminal/activityChannel.js +166 -0
  81. package/dist/server/terminal/activityChannel.js.map +1 -0
  82. package/dist/server/terminal/agentTranscriptStatus.d.ts +12 -0
  83. package/dist/server/terminal/agentTranscriptStatus.js +78 -7
  84. package/dist/server/terminal/agentTranscriptStatus.js.map +1 -1
  85. package/dist/server/terminal/codexTranscriptSource.d.ts +2 -0
  86. package/dist/server/terminal/codexTranscriptSource.js +41 -37
  87. package/dist/server/terminal/codexTranscriptSource.js.map +1 -1
  88. package/dist/server/terminal/subagentSources.js +2 -1
  89. package/dist/server/terminal/subagentSources.js.map +1 -1
  90. package/dist/server/terminal/transcriptHeader.d.ts +85 -0
  91. package/dist/server/terminal/transcriptHeader.js +376 -0
  92. package/dist/server/terminal/transcriptHeader.js.map +1 -0
  93. package/dist/server/terminal/transcriptHistory.d.ts +16 -2
  94. package/dist/server/terminal/transcriptHistory.js +120 -21
  95. package/dist/server/terminal/transcriptHistory.js.map +1 -1
  96. package/dist/server/terminal/transcriptStore.d.ts +6 -0
  97. package/dist/server/terminal/transcriptStore.js +222 -26
  98. package/dist/server/terminal/transcriptStore.js.map +1 -1
  99. package/dist/shared/activityProbe.d.ts +10 -0
  100. package/dist/shared/activityProbe.js +24 -0
  101. package/dist/shared/activityProbe.js.map +1 -0
  102. package/dist/shared/protocol.d.ts +45 -0
  103. package/dist/shared/protocol.js.map +1 -1
  104. package/dist/shared/types.d.ts +9 -1
  105. package/docs/features.md +10 -0
  106. package/docs/provider-hooks.md +287 -0
  107. package/docs/terminal-history.md +10 -0
  108. package/package.json +2 -1
  109. package/scripts/nterminal-hook.cjs +171 -0
  110. package/scripts/nterminalctl +26 -2
  111. package/dist/client/assets/MarkdownPreview-DjDO4lEl.js +0 -1
  112. package/dist/client/assets/index-CIYazAGv.css +0 -1
  113. package/dist/client/assets/index-DwvLN_WJ.js +0 -56
@@ -0,0 +1,200 @@
1
+ import { createHash } from 'node:crypto';
2
+ // Per-tool-call events (sync or `async: true` registrations) and child-agent
3
+ // events. They only ever mark a session working, so under queue pressure
4
+ // they are coalesced or dropped before any start/stop/completion event.
5
+ const LOW_PRIORITY_EVENTS = new Set(['PreToolUse', 'PostToolUse', 'PostToolUseFailure']);
6
+ export function isLowPriorityLifecycleEvent(event) {
7
+ return LOW_PRIORITY_EVENTS.has(event.event) || event.event.startsWith('Subagent') || Boolean(event.agentId) || Boolean(event.background);
8
+ }
9
+ export function reduceLifecycle(previous, event) {
10
+ // Child hooks carry the parent's session ID in some providers. They must not
11
+ // change the parent's state or create a second parent completion.
12
+ if (event.agentId || event.background || event.event.startsWith('Subagent'))
13
+ return previous;
14
+ const at = Date.parse(event.occurredAt);
15
+ if (!Number.isFinite(at))
16
+ return previous;
17
+ if (previous && at < previous.lastEventAt)
18
+ return previous;
19
+ const sameSession = previous?.status.provider === event.provider && previous.status.sessionId === event.sessionId;
20
+ const old = sameSession ? previous : undefined;
21
+ if (old?.seen.includes(event.eventId) || (old && at < old.lastEventAt))
22
+ return previous;
23
+ const turn = event.turnId ?? event.promptId ?? null;
24
+ if (old && turn && old.finishedTurns.includes(turn))
25
+ return previous;
26
+ const closed = old && ['done', 'stopped', 'idle'].includes(old.status.state);
27
+ if (old?.recovery?.activeTurn && event.event === 'StopFailure') {
28
+ if (!turn)
29
+ return previous;
30
+ if (turn === old.recovery.turn) {
31
+ if (at < old.recovery.after || old.recovery.failure)
32
+ return previous;
33
+ // Candidate failure is not evidence against A. Keep A's watermark so
34
+ // an earlier-captured continuation can still invalidate this candidate.
35
+ return { ...old, seen: [...old.seen, event.eventId].slice(-128),
36
+ recovery: { ...old.recovery, failure: { eventId: event.eventId, occurredAt: event.occurredAt } } };
37
+ }
38
+ }
39
+ if (old && event.provider === 'claude' && event.event === 'Stop' && (turn ? turn !== old.turn && (old.turn || closed) : closed)) {
40
+ if (at <= old.lastEventAt || (old.recovery && at <= old.recovery.after))
41
+ return previous;
42
+ if (old.recovery?.failure) {
43
+ // Another provisional Stop cannot erase failure or move its proof
44
+ // boundary. A genuine prompt/current-turn continuation can supersede it.
45
+ if (turn !== old.recovery.turn)
46
+ return previous;
47
+ return { ...old, seen: [...old.seen, event.eventId].slice(-128) };
48
+ }
49
+ // Stop timestamps may be delivery times. A delayed hook is not enough
50
+ // to retire an active turn or prevent that turn's later hooks arriving.
51
+ return { ...old, seen: [...old.seen, event.eventId].slice(-128),
52
+ recovery: { turn, after: at, activeTurn: !closed } };
53
+ }
54
+ const recoveringNewTurn = Boolean(old && turn && old.turn !== turn && closed
55
+ && ['PreToolUse', 'PostToolUse', 'PostToolUseFailure', 'agent-turn-complete', 'StopFailure'].includes(event.event));
56
+ if (old?.turn && turn && old.turn !== turn && !recoveringNewTurn && !['UserPromptSubmit', 'SessionStart'].includes(event.event))
57
+ return previous;
58
+ const next = {
59
+ status: { provider: event.provider, sessionId: event.sessionId, state: 'idle', source: 'hook', ...old?.status },
60
+ turn: old?.turn ?? turn,
61
+ segment: old?.segment ?? 0,
62
+ lastEventAt: at,
63
+ seen: [...(old?.seen ?? []), event.eventId].slice(-128),
64
+ finishedTurns: old?.finishedTurns ?? [],
65
+ stopPending: old?.stopPending ?? false,
66
+ pendingWork: old?.pendingWork ?? false,
67
+ ...(old?.recovery ? { recovery: old.recovery } : {})
68
+ };
69
+ const finish = (outcome) => {
70
+ const identity = turn ?? next.turn ?? `segment:${next.segment}`;
71
+ const id = createHash('sha256').update(JSON.stringify([event.provider, event.sessionId, identity, outcome])).digest('hex');
72
+ next.status = { ...next.status, state: outcome === 'finished' ? 'done' : 'stopped', completion: { id, outcome, occurredAt: event.occurredAt } };
73
+ next.stopPending = false;
74
+ delete next.recovery;
75
+ if (turn ?? next.turn)
76
+ next.finishedTurns = [...next.finishedTurns, (turn ?? next.turn)].slice(-128);
77
+ };
78
+ if (recoveringNewTurn) {
79
+ if (old?.turn)
80
+ next.finishedTurns = [...next.finishedTurns, old.turn].slice(-128);
81
+ next.turn = turn;
82
+ next.segment++;
83
+ next.pendingWork = false;
84
+ delete next.recovery;
85
+ }
86
+ switch (event.event) {
87
+ case 'SessionStart':
88
+ // Compact/resume hooks are not proof that an active turn finished.
89
+ break;
90
+ case 'UserPromptSubmit':
91
+ if (!turn || turn !== old?.turn)
92
+ next.segment += 1;
93
+ // A new prompt also retires the preceding turn, even when it was
94
+ // interrupted before a completion hook could close it.
95
+ if (turn && old?.turn && turn !== old.turn)
96
+ next.finishedTurns = [...next.finishedTurns, old.turn].slice(-128);
97
+ next.turn = turn;
98
+ next.stopPending = false;
99
+ next.pendingWork = false;
100
+ delete next.recovery;
101
+ next.status.state = 'working';
102
+ break;
103
+ case 'PreToolUse':
104
+ case 'PostToolUse':
105
+ case 'PostToolUseFailure':
106
+ if (!turn && (old?.status.state === 'done' || old?.status.state === 'stopped'))
107
+ return previous;
108
+ next.turn = turn ?? next.turn;
109
+ next.stopPending = false;
110
+ delete next.recovery;
111
+ next.status.state = 'working';
112
+ break;
113
+ case 'PermissionRequest':
114
+ delete next.recovery;
115
+ next.status.state = 'waiting';
116
+ break;
117
+ case 'Notification':
118
+ if (event.notificationType === 'permission_prompt')
119
+ next.status.state = 'waiting';
120
+ else if (event.notificationType === 'idle_prompt' && next.stopPending && !old?.pendingWork && !next.recovery)
121
+ finish('finished');
122
+ else
123
+ return previous;
124
+ break;
125
+ case 'Stop':
126
+ delete next.recovery;
127
+ next.status.state = 'finishing';
128
+ next.stopPending = true;
129
+ if (typeof event.hasBackgroundTasks === 'boolean')
130
+ next.pendingWork = event.hasBackgroundTasks;
131
+ break;
132
+ case 'agent-turn-complete':
133
+ if (event.provider !== 'codex')
134
+ return previous;
135
+ finish('finished');
136
+ break;
137
+ case 'StopFailure':
138
+ case 'Interrupt':
139
+ finish('stopped');
140
+ break;
141
+ case 'SessionEnd':
142
+ if (old && ['working', 'finishing', 'waiting'].includes(old.status.state))
143
+ finish('stopped');
144
+ else
145
+ next.status.state = 'idle';
146
+ break;
147
+ default:
148
+ return previous;
149
+ }
150
+ return next;
151
+ }
152
+ /** Confirm from a post-turn marker, not from assistant text or inactivity. */
153
+ export function reconcileLifecycle(previous, completion) {
154
+ if (!completion || (['done', 'stopped'].includes(previous.status.state) && !previous.recovery))
155
+ return previous;
156
+ const at = Date.parse(completion.occurredAt);
157
+ const turn = completion.turnId ?? completion.promptId;
158
+ const eventId = `transcript:${completion.id}`;
159
+ if (!Number.isFinite(at) || at < previous.lastEventAt || previous.seen.includes(eventId)
160
+ || (turn && previous.finishedTurns.includes(turn)))
161
+ return previous;
162
+ const recovery = previous.recovery;
163
+ let recovering = false;
164
+ if (recovery) {
165
+ if (at <= recovery.after)
166
+ return previous;
167
+ const matching = !turn || !recovery.turn || turn === recovery.turn;
168
+ // When another turn is still active, an anonymous marker cannot tell a
169
+ // lost new prompt from a delayed Stop. Require its explicit turn identity.
170
+ recovering = matching && (!recovery.activeTurn || Boolean(turn && turn === recovery.turn));
171
+ if (!recovering && (!turn || turn !== previous.turn))
172
+ return previous;
173
+ }
174
+ if (!recovering && turn && previous.turn && turn !== previous.turn)
175
+ return previous;
176
+ const failure = recovering ? recovery?.failure : undefined;
177
+ const confirmedTurn = recovering ? turn ?? recovery.turn : turn ?? previous.turn;
178
+ const next = { ...previous, status: { ...previous.status }, lastEventAt: Math.max(at, failure ? Date.parse(failure.occurredAt) : at),
179
+ turn: confirmedTurn ?? null, seen: [...previous.seen, eventId].slice(-128), pendingWork: completion.pending };
180
+ delete next.recovery;
181
+ if (recovering) {
182
+ next.segment++;
183
+ next.stopPending = true;
184
+ if (previous.turn && previous.turn !== confirmedTurn)
185
+ next.finishedTurns = [...next.finishedTurns, previous.turn].slice(-128);
186
+ }
187
+ if (completion.pending && !failure) {
188
+ next.status.state = 'waiting';
189
+ return next;
190
+ }
191
+ const outcome = failure || completion.kind === 'turn_aborted' ? 'stopped' : 'finished';
192
+ const identity = confirmedTurn ?? `transcript:${completion.id}`;
193
+ const id = createHash('sha256').update(JSON.stringify([previous.status.provider, previous.status.sessionId, identity, outcome])).digest('hex');
194
+ next.status = { ...next.status, state: outcome === 'finished' ? 'done' : 'stopped', completion: { id, outcome, occurredAt: failure?.occurredAt ?? completion.occurredAt } };
195
+ next.stopPending = false;
196
+ if (confirmedTurn)
197
+ next.finishedTurns = [...next.finishedTurns, confirmedTurn].slice(-128);
198
+ return next;
199
+ }
200
+ //# sourceMappingURL=lifecycle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../../../src/server/hooks/lifecycle.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { type LockIdentity } from './verifiedLock.js';
2
+ /** Caller must hold the distinct verified publication guard through release. */
3
+ export declare function acquirePublicationGate(directory: string, owner: LockIdentity, procRoot?: string): Promise<() => Promise<void>>;
@@ -0,0 +1,137 @@
1
+ import { constants } from 'node:fs';
2
+ import { link, lstat, open, unlink } from 'node:fs/promises';
3
+ import { randomUUID } from 'node:crypto';
4
+ import path from 'node:path';
5
+ import { missing, safeParents, syncDirectory } from './hookFiles.js';
6
+ import { VerifiedLockError, isLockIdentity, ownerIsDead } from './verifiedLock.js';
7
+ const UUID = '[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}';
8
+ const unavailable = () => new VerifiedLockError('publication_lock_unsafe');
9
+ // This reader alone accepts two links: the gate plus its exactly identified
10
+ // prepared file. Generic helper/config snapshots still reject all hard links.
11
+ async function readGate(file) {
12
+ await safeParents(file);
13
+ let handle;
14
+ try {
15
+ handle = await open(file, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
16
+ }
17
+ catch (error) {
18
+ if (missing(error))
19
+ return null;
20
+ throw unavailable();
21
+ }
22
+ try {
23
+ const info = await handle.stat();
24
+ if (!info.isFile() || info.uid !== process.getuid?.() || (info.mode & 0o777) !== 0o600
25
+ || info.size > 4096 || (info.nlink !== 1 && info.nlink !== 2))
26
+ throw unavailable();
27
+ const buffer = Buffer.alloc(4097);
28
+ const { bytesRead } = await handle.read(buffer, 0, buffer.length, 0);
29
+ if (bytesRead > 4096)
30
+ throw unavailable();
31
+ const text = new TextDecoder('utf-8', { fatal: true }).decode(buffer.subarray(0, bytesRead));
32
+ let value;
33
+ try {
34
+ value = JSON.parse(text);
35
+ }
36
+ catch {
37
+ throw unavailable();
38
+ }
39
+ if (!value || value.version !== 1 || value.kind !== 'nterminal-hook-publication' || !isLockIdentity(value.owner)
40
+ || typeof value.token !== 'string' || !new RegExp(`^${UUID}$`).test(value.token)
41
+ || value.prepared !== `.endpoint-owner-${value.token}.tmp`)
42
+ throw unavailable();
43
+ if (info.nlink === 2) {
44
+ const prepared = await lstat(path.join(path.dirname(file), value.prepared)).catch(() => null);
45
+ if (!prepared?.isFile() || prepared.ino !== info.ino || prepared.dev !== info.dev || prepared.nlink !== 2)
46
+ throw unavailable();
47
+ }
48
+ return { value, text, ino: info.ino, dev: info.dev, nlink: info.nlink };
49
+ }
50
+ finally {
51
+ await handle.close();
52
+ }
53
+ }
54
+ function same(a, b) {
55
+ return !!a && a.ino === b.ino && a.dev === b.dev && a.text === b.text;
56
+ }
57
+ async function removeGate(file, expected) {
58
+ const current = await readGate(file);
59
+ if (!same(current, expected))
60
+ throw unavailable();
61
+ if (current.nlink === 2) {
62
+ await unlink(path.join(path.dirname(file), current.value.prepared));
63
+ if (!same(await readGate(file), expected))
64
+ throw unavailable();
65
+ }
66
+ await unlink(file);
67
+ await syncDirectory(path.dirname(file));
68
+ }
69
+ /** Caller must hold the distinct verified publication guard through release. */
70
+ export async function acquirePublicationGate(directory, owner, procRoot = '/proc') {
71
+ const file = path.join(directory, '.endpoint-lock');
72
+ const existing = await readGate(file);
73
+ if (existing) {
74
+ if (!await ownerIsDead(existing.value.owner, owner, procRoot))
75
+ throw new VerifiedLockError('publication_busy', true);
76
+ await removeGate(file, existing);
77
+ }
78
+ const token = randomUUID();
79
+ const value = { version: 1, kind: 'nterminal-hook-publication', owner, token, prepared: `.endpoint-owner-${token}.tmp` };
80
+ const temporary = path.join(directory, value.prepared);
81
+ const text = JSON.stringify(value);
82
+ let acquired;
83
+ let created;
84
+ try {
85
+ const handle = await open(temporary, 'wx', 0o600);
86
+ try {
87
+ const info = await handle.stat();
88
+ created = { value, text, ino: info.ino, dev: info.dev, nlink: 1 };
89
+ await handle.chmod(0o600);
90
+ await handle.writeFile(text);
91
+ await handle.sync();
92
+ }
93
+ finally {
94
+ await handle.close();
95
+ }
96
+ try {
97
+ await link(temporary, file);
98
+ }
99
+ catch (error) {
100
+ // Never remove an EEXIST replacement: an old mkdir publisher can win the
101
+ // gap following stale-record reclamation. Unknown old locks fail closed.
102
+ if (error.code === 'EEXIST') {
103
+ const winner = await readGate(file);
104
+ if (winner && !await ownerIsDead(winner.value.owner, owner, procRoot))
105
+ throw new VerifiedLockError('publication_busy', true);
106
+ throw unavailable();
107
+ }
108
+ throw new VerifiedLockError('lock_link_unavailable');
109
+ }
110
+ acquired = created;
111
+ await syncDirectory(directory);
112
+ if (!same(await readGate(file), acquired))
113
+ throw unavailable();
114
+ await unlink(temporary);
115
+ await syncDirectory(directory);
116
+ const lease = acquired;
117
+ return () => removeGate(file, lease);
118
+ }
119
+ catch (error) {
120
+ if (acquired)
121
+ await removeGate(file, acquired);
122
+ throw error;
123
+ }
124
+ finally {
125
+ // Only this unique, verified prepared inode belongs to us.
126
+ if (created) {
127
+ const remaining = await lstat(temporary).catch((error) => { if (!missing(error))
128
+ throw error; return null; });
129
+ if (remaining) {
130
+ if (!remaining.isFile() || remaining.ino !== created.ino || remaining.dev !== created.dev)
131
+ throw unavailable();
132
+ await unlink(temporary);
133
+ }
134
+ }
135
+ }
136
+ }
137
+ //# sourceMappingURL=publicationLock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publicationLock.js","sourceRoot":"","sources":["../../../src/server/hooks/publicationLock.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { HookControlError } from './hookFiles.js';
2
+ export declare class VerifiedLockError extends HookControlError {
3
+ readonly retryable: boolean;
4
+ readonly detail: string;
5
+ constructor(code: string, retryable?: boolean, detail?: string);
6
+ }
7
+ export interface VerifiedLockLease {
8
+ identity: LockIdentity;
9
+ token: string;
10
+ release(): Promise<void>;
11
+ }
12
+ export type LockIdentity = {
13
+ host: string;
14
+ boot: string;
15
+ namespace: string;
16
+ pid: number;
17
+ ticks: string;
18
+ };
19
+ export declare function readLockIdentity(procRoot?: string, machineIdPath?: string): Promise<LockIdentity>;
20
+ export declare function acquireVerifiedLock(directory: string, procRoot?: string, machineIdPath?: string): Promise<VerifiedLockLease>;
21
+ export declare function isLockIdentity(value: unknown): value is LockIdentity;
22
+ export declare function ownerIsDead(owner: Omit<LockIdentity, 'host'> & {
23
+ host: string | null;
24
+ }, own: LockIdentity, procRoot?: string): Promise<boolean>;
@@ -0,0 +1,207 @@
1
+ import { lstat, mkdir, readdir, readlink, rmdir, unlink } from 'node:fs/promises';
2
+ import { createHash, randomUUID } from 'node:crypto';
3
+ import path from 'node:path';
4
+ import { HookControlError, ensureDirectory, missing, replace, snapshot } from './hookFiles.js';
5
+ export class VerifiedLockError extends HookControlError {
6
+ retryable;
7
+ detail;
8
+ constructor(code, retryable = false, detail = code) {
9
+ super(code);
10
+ this.retryable = retryable;
11
+ this.detail = detail;
12
+ }
13
+ }
14
+ function record(value) { return value !== null && typeof value === 'object' && !Array.isArray(value); }
15
+ function digest(text) { return createHash('sha256').update(text).digest('hex'); }
16
+ const UUID = '[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}';
17
+ const CLAIM_NAME = new RegExp(`^v2-([a-f0-9]{64})-(${UUID})-(\\d{1,20})-([1-9]\\d{0,9})-(\\d{1,20})-(${UUID})$`);
18
+ const LEGACY_CLAIM_NAME = new RegExp(`^v1-(${UUID})-(\\d{1,20})-([1-9]\\d{0,9})-(\\d{1,20})-(${UUID})$`);
19
+ const MAX_LIVE_CLAIMS = 128;
20
+ const MAX_CLAIM_SCAN = 256;
21
+ async function processIdentity(procRoot, pid) {
22
+ const saved = await snapshot(path.join(procRoot, String(pid), 'stat'), false);
23
+ if (!saved)
24
+ return null;
25
+ const end = saved.text.lastIndexOf(')');
26
+ const fields = saved.text.slice(end + 2).trim().split(/\s+/);
27
+ if (!saved.text.startsWith(`${pid} (`) || end < 0 || !/^[A-Za-z]$/.test(fields[0] ?? '')
28
+ || !/^\d{1,20}$/.test(fields[19] ?? ''))
29
+ throw new VerifiedLockError('lock_identity_unavailable');
30
+ return { ticks: fields[19], exited: fields[0] === 'Z' || fields[0] === 'X' };
31
+ }
32
+ export async function readLockIdentity(procRoot = '/proc', machineIdPath = '/etc/machine-id') {
33
+ try {
34
+ // Android/container hosts may omit or deny machine-id. Boot/process identity
35
+ // remains mandatory; only stable cross-boot recovery is lost in that case.
36
+ const machineId = (await snapshot(machineIdPath, false).catch(() => null))?.text.trim().toLowerCase();
37
+ const boot = (await snapshot(path.join(procRoot, 'sys/kernel/random/boot_id'), false))?.text.trim();
38
+ const namespace = /^pid:\[(\d{1,20})\]$/.exec(await readlink(path.join(procRoot, 'self/ns/pid')))?.[1];
39
+ const own = await processIdentity(procRoot, process.pid);
40
+ if (!boot || !new RegExp(`^${UUID}$`).test(boot) || !namespace || !own || own.exited)
41
+ throw new Error();
42
+ const host = machineId && /^[a-f0-9]{32}$/.test(machineId) && !/^0+$/.test(machineId)
43
+ ? digest(`nterminal-hook-lock-host\0${machineId}`) : digest(`nterminal-hook-lock-boot\0${boot}`);
44
+ return { host, boot, namespace, pid: process.pid, ticks: own.ticks };
45
+ }
46
+ catch {
47
+ throw new VerifiedLockError('lock_identity_unavailable');
48
+ }
49
+ }
50
+ async function legacyLockAbsent(directory) {
51
+ try {
52
+ await lstat(directory);
53
+ }
54
+ catch (error) {
55
+ if (missing(error))
56
+ return;
57
+ throw error;
58
+ }
59
+ // Old empty mkdir locks carry no owner identity and cannot be safely reclaimed.
60
+ throw new VerifiedLockError('installation_busy');
61
+ }
62
+ async function snapshotClaimFile(target) {
63
+ try {
64
+ return await snapshot(target);
65
+ }
66
+ catch (error) {
67
+ if (error instanceof HookControlError && error.code === 'unsafe_path') {
68
+ // Another cleanup can unlink an opened ticket before snapshot checks nlink.
69
+ // Only confirmed disappearance is benign; existing replacements still fail.
70
+ try {
71
+ await lstat(target);
72
+ }
73
+ catch (currentError) {
74
+ if (missing(currentError))
75
+ return null;
76
+ throw currentError;
77
+ }
78
+ }
79
+ throw error;
80
+ }
81
+ }
82
+ async function removeClaim(directory) {
83
+ let names;
84
+ try {
85
+ names = await readdir(directory);
86
+ }
87
+ catch (error) {
88
+ if (missing(error))
89
+ return;
90
+ throw error;
91
+ }
92
+ if (names.length > 16 || names.some((name) => name !== 'ticket.json'
93
+ && !new RegExp(`^ticket\\.json\\.nterminal-${UUID}\\.tmp$`).test(name)))
94
+ throw new VerifiedLockError('installation_busy');
95
+ for (const name of names) {
96
+ const target = path.join(directory, name);
97
+ await snapshotClaimFile(target);
98
+ await unlink(target).catch((error) => { if (!missing(error))
99
+ throw error; });
100
+ }
101
+ await rmdir(directory).catch((error) => { if (!missing(error))
102
+ throw error; });
103
+ }
104
+ async function claims(directory, own, procRoot) {
105
+ const result = [];
106
+ const names = await readdir(directory);
107
+ // Oversized sets still make bounded cleanup progress. Never admit an owner
108
+ // without inspecting the entire remaining contention set.
109
+ for (const name of names.slice(0, MAX_CLAIM_SCAN)) {
110
+ const match = CLAIM_NAME.exec(name);
111
+ const legacy = match ? null : LEGACY_CLAIM_NAME.exec(name);
112
+ if (!match && !legacy)
113
+ throw new VerifiedLockError('installation_busy');
114
+ const parts = match ? match.slice(2) : legacy.slice(1);
115
+ const claim = { name, host: match?.[1] ?? null, boot: parts[0], namespace: parts[1], pid: Number(parts[2]), ticks: parts[3] };
116
+ const location = path.join(directory, name);
117
+ let info;
118
+ try {
119
+ info = await lstat(location);
120
+ }
121
+ catch (error) {
122
+ if (missing(error))
123
+ continue;
124
+ throw error;
125
+ }
126
+ if (!info.isDirectory() || info.isSymbolicLink() || (process.getuid && info.uid !== process.getuid())) {
127
+ throw new VerifiedLockError('unsafe_path');
128
+ }
129
+ const dead = await ownerIsDead(claim, own, procRoot);
130
+ if (dead) {
131
+ await removeClaim(location);
132
+ continue;
133
+ }
134
+ const saved = await snapshotClaimFile(path.join(location, 'ticket.json'));
135
+ if (!saved) {
136
+ result.push({ ...claim, ticket: null });
137
+ continue;
138
+ }
139
+ let value;
140
+ try {
141
+ value = JSON.parse(saved.text);
142
+ }
143
+ catch {
144
+ throw new VerifiedLockError('installation_busy');
145
+ }
146
+ if (!record(value) || value.version !== 1 || typeof value.ticket !== 'string' || !/^[1-9]\d{0,19}$/.test(value.ticket)) {
147
+ throw new VerifiedLockError('installation_busy');
148
+ }
149
+ result.push({ ...claim, ticket: BigInt(value.ticket) });
150
+ }
151
+ if (names.length > MAX_CLAIM_SCAN || result.length > MAX_LIVE_CLAIMS)
152
+ throw new VerifiedLockError('installation_busy', true, 'capacity');
153
+ return result;
154
+ }
155
+ export async function acquireVerifiedLock(directory, procRoot = '/proc', machineIdPath = '/etc/machine-id') {
156
+ await legacyLockAbsent(directory);
157
+ const identity = await readLockIdentity(procRoot, machineIdPath);
158
+ const owners = `${directory}.owners`;
159
+ await ensureDirectory(owners);
160
+ const token = randomUUID();
161
+ const name = `v2-${identity.host}-${identity.boot}-${identity.namespace}-${identity.pid}-${identity.ticks}-${token}`;
162
+ const location = path.join(owners, name);
163
+ // A fail-fast Lamport bakery lock: publish "choosing" atomically in the
164
+ // identity-bearing directory name, then choose max(ticket)+1. Later entrants
165
+ // cannot outrank an admitted owner. Unique claim paths make both crash cleanup
166
+ // and release safe without a check-then-unlink race on a shared lock pathname.
167
+ await mkdir(location, { mode: 0o700 });
168
+ const release = () => removeClaim(location);
169
+ try {
170
+ const observed = await claims(owners, identity, procRoot);
171
+ const ticket = observed.reduce((max, claim) => claim.ticket !== null && claim.ticket > max ? claim.ticket : max, 0n) + 1n;
172
+ if (ticket.toString().length > 20)
173
+ throw new VerifiedLockError('installation_busy');
174
+ await replace(path.join(location, 'ticket.json'), null, JSON.stringify({ version: 1, ticket: ticket.toString() }));
175
+ await legacyLockAbsent(directory);
176
+ for (const claim of await claims(owners, identity, procRoot)) {
177
+ if (claim.name !== name && (claim.ticket === null || claim.ticket < ticket || (claim.ticket === ticket && claim.name < name))) {
178
+ throw new VerifiedLockError('installation_busy', true, 'contended');
179
+ }
180
+ }
181
+ return { identity, token, release };
182
+ }
183
+ catch (error) {
184
+ await release();
185
+ throw error;
186
+ }
187
+ }
188
+ export function isLockIdentity(value) {
189
+ return record(value) && typeof value.host === 'string' && /^[a-f0-9]{64}$/.test(value.host)
190
+ && typeof value.boot === 'string' && new RegExp(`^${UUID}$`).test(value.boot)
191
+ && typeof value.namespace === 'string' && /^\d{1,20}$/.test(value.namespace)
192
+ && Number.isSafeInteger(value.pid) && Number(value.pid) > 0 && Number(value.pid) <= 0x7fffffff
193
+ && typeof value.ticks === 'string' && /^\d{1,20}$/.test(value.ticks);
194
+ }
195
+ export async function ownerIsDead(owner, own, procRoot = '/proc') {
196
+ if (owner.host !== null && owner.host !== own.host)
197
+ throw new VerifiedLockError('lock_host_mismatch');
198
+ if (owner.host === null && owner.boot !== own.boot)
199
+ throw new VerifiedLockError('lock_host_unknown');
200
+ if (owner.boot !== own.boot)
201
+ return true;
202
+ if (owner.namespace !== own.namespace)
203
+ throw new VerifiedLockError('installation_busy', false, 'foreign_namespace');
204
+ const current = await processIdentity(procRoot, owner.pid);
205
+ return !current || current.exited || current.ticks !== owner.ticks;
206
+ }
207
+ //# sourceMappingURL=verifiedLock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verifiedLock.js","sourceRoot":"","sources":["../../../src/server/hooks/verifiedLock.ts"],"names":[],"mappings":"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"}
@@ -12,8 +12,12 @@ import { type PushNotificationRouteServices } from './routes/pushNotificationRou
12
12
  import { type CodeServerRouteServices } from './routes/codeServerRoutes.js';
13
13
  import { type AccountRouteServices } from './routes/accountRoutes.js';
14
14
  import { type FavoriteRouteServices } from './routes/favoriteRoutes.js';
15
+ import { type HookRouteServices } from './routes/hookRoutes.js';
16
+ import type { TerminalActivityChannel } from './terminal/activityChannel.js';
15
17
  export interface BuildAppServices extends AuthRouteServices, TerminalRouteServices, TerminalLayoutRouteServices, UploadRouteServices, FileRouteServices, AgentRouteServices, AgentManagementRouteServices, NotificationAssetRouteServices, PushNotificationRouteServices, FavoriteRouteServices, Omit<Partial<AccountRouteServices>, 'authService'> {
16
18
  codeServerManager?: CodeServerRouteServices['codeServerManager'];
19
+ hookInstallation?: NonNullable<HookRouteServices['hookInstallation']>;
20
+ activityChannel?: TerminalActivityChannel;
17
21
  }
18
22
  export declare const webSocketMaxPayloadBytes: number;
19
23
  export declare function buildApp(config: AppConfig, services: BuildAppServices): Promise<FastifyInstance>;