@tienne/gestalt 0.108.0 → 0.109.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.
Files changed (69) hide show
  1. package/CLAUDE.md +1 -0
  2. package/dist/package.json +1 -1
  3. package/dist/src/cli/commands/peer.d.ts +19 -0
  4. package/dist/src/cli/commands/peer.d.ts.map +1 -0
  5. package/dist/src/cli/commands/peer.js +147 -0
  6. package/dist/src/cli/commands/peer.js.map +1 -0
  7. package/dist/src/cli/index.d.ts.map +1 -1
  8. package/dist/src/cli/index.js +35 -2
  9. package/dist/src/cli/index.js.map +1 -1
  10. package/dist/src/peer/client.d.ts +9 -0
  11. package/dist/src/peer/client.d.ts.map +1 -0
  12. package/dist/src/peer/client.js +51 -0
  13. package/dist/src/peer/client.js.map +1 -0
  14. package/dist/src/peer/daemon.d.ts +71 -0
  15. package/dist/src/peer/daemon.d.ts.map +1 -0
  16. package/dist/src/peer/daemon.js +407 -0
  17. package/dist/src/peer/daemon.js.map +1 -0
  18. package/dist/src/peer/errors.d.ts +2 -0
  19. package/dist/src/peer/errors.d.ts.map +1 -0
  20. package/dist/src/peer/errors.js +4 -0
  21. package/dist/src/peer/errors.js.map +1 -0
  22. package/dist/src/peer/index.d.ts +14 -0
  23. package/dist/src/peer/index.d.ts.map +1 -0
  24. package/dist/src/peer/index.js +9 -0
  25. package/dist/src/peer/index.js.map +1 -0
  26. package/dist/src/peer/locate.d.ts +44 -0
  27. package/dist/src/peer/locate.d.ts.map +1 -0
  28. package/dist/src/peer/locate.js +116 -0
  29. package/dist/src/peer/locate.js.map +1 -0
  30. package/dist/src/peer/paths.d.ts +23 -0
  31. package/dist/src/peer/paths.d.ts.map +1 -0
  32. package/dist/src/peer/paths.js +50 -0
  33. package/dist/src/peer/paths.js.map +1 -0
  34. package/dist/src/peer/protocol.d.ts +61 -0
  35. package/dist/src/peer/protocol.d.ts.map +1 -0
  36. package/dist/src/peer/protocol.js +7 -0
  37. package/dist/src/peer/protocol.js.map +1 -0
  38. package/dist/src/peer/redact.d.ts +30 -0
  39. package/dist/src/peer/redact.d.ts.map +1 -0
  40. package/dist/src/peer/redact.js +214 -0
  41. package/dist/src/peer/redact.js.map +1 -0
  42. package/dist/src/peer/share.d.ts +123 -0
  43. package/dist/src/peer/share.d.ts.map +1 -0
  44. package/dist/src/peer/share.js +204 -0
  45. package/dist/src/peer/share.js.map +1 -0
  46. package/dist/src/peer/state.d.ts +37 -0
  47. package/dist/src/peer/state.d.ts.map +1 -0
  48. package/dist/src/peer/state.js +99 -0
  49. package/dist/src/peer/state.js.map +1 -0
  50. package/dist/src/peer/tail.d.ts +55 -0
  51. package/dist/src/peer/tail.d.ts.map +1 -0
  52. package/dist/src/peer/tail.js +148 -0
  53. package/dist/src/peer/tail.js.map +1 -0
  54. package/dist/src/peer/transform.d.ts +79 -0
  55. package/dist/src/peer/transform.d.ts.map +1 -0
  56. package/dist/src/peer/transform.js +237 -0
  57. package/dist/src/peer/transform.js.map +1 -0
  58. package/dist/src/peer/viewer-html.d.ts +10 -0
  59. package/dist/src/peer/viewer-html.d.ts.map +1 -0
  60. package/dist/src/peer/viewer-html.js +157 -0
  61. package/dist/src/peer/viewer-html.js.map +1 -0
  62. package/dist/src/peer/viewer.d.ts +58 -0
  63. package/dist/src/peer/viewer.d.ts.map +1 -0
  64. package/dist/src/peer/viewer.js +249 -0
  65. package/dist/src/peer/viewer.js.map +1 -0
  66. package/package.json +1 -1
  67. package/plugin/.codex-plugin/plugin.json +1 -1
  68. package/plugin/.mcp.json +1 -1
  69. package/plugin/mcp.json +1 -1
@@ -0,0 +1,407 @@
1
+ import { randomBytes } from 'node:crypto';
2
+ import { chmodSync, existsSync, linkSync, lstatSync, realpathSync, statSync, unlinkSync, } from 'node:fs';
3
+ import { createConnection, createServer } from 'node:net';
4
+ import { isAbsolute, join } from 'node:path';
5
+ import { isToolsLevel } from './redact.js';
6
+ import { ensurePrivateDir, MAX_SOCKET_PATH_BYTES, socketPath, statePath } from './paths.js';
7
+ import { PeerState } from './state.js';
8
+ import { ShareStream } from './share.js';
9
+ import { ViewerServer } from './viewer.js';
10
+ import { DEFAULT_EXPIRES_MINUTES, MAX_EXPIRES_MINUTES, MAX_REQUEST_BYTES } from './protocol.js';
11
+ import { isSessionId } from './locate.js';
12
+ import { errMessage } from './errors.js';
13
+ const DEFAULT_POLL_MS = 500;
14
+ /** stop이 IPC 서버가 닫히길 기다리는 상한. 넘으면 기다리지 않고 정리를 마친다 */
15
+ const STOP_TIMEOUT_MS = 2_000;
16
+ /**
17
+ * `gestalt peer daemon`. 공유를 들고 대화 기록을 따라 읽어 로컬 뷰어로 흘린다.
18
+ *
19
+ * 바깥으로 나가는 연결이 하나도 없다. 소켓은 0600, 디렉토리는 0700이라 같은 OS
20
+ * 사용자만 명령을 넣는다. 뷰어는 `127.0.0.1`에만 붙는다.
21
+ */
22
+ export class PeerDaemon {
23
+ options;
24
+ ipc = null;
25
+ viewer;
26
+ state = null;
27
+ shares = new Map();
28
+ timer = null;
29
+ startedAt = 0;
30
+ conns = new Set();
31
+ /** 이 데몬이 만든 소켓 파일. stop은 소켓 자리가 아직 이것일 때만 지운다 */
32
+ ownSocket = null;
33
+ sock;
34
+ /** listen할 임시 이름. 권한을 좁힌 뒤 진짜 이름으로 링크한다 */
35
+ tmpSock;
36
+ pollMs;
37
+ constructor(options) {
38
+ this.options = options;
39
+ this.sock = socketPath(options.root);
40
+ this.tmpSock = join(options.root, `${process.pid}.s`);
41
+ this.pollMs = options.pollMs ?? DEFAULT_POLL_MS;
42
+ this.viewer = new ViewerServer({
43
+ lookup: (id) => {
44
+ const s = this.shares.get(id);
45
+ return s ? { stream: s.stream, token: s.token } : undefined;
46
+ },
47
+ onConnect: (id) => this.state?.audit('viewer_connect', id),
48
+ onDisconnect: (id) => this.state?.audit('viewer_disconnect', id),
49
+ });
50
+ }
51
+ get socketPath() {
52
+ return this.sock;
53
+ }
54
+ get viewerPort() {
55
+ return this.viewer.port;
56
+ }
57
+ async start() {
58
+ for (const path of [this.sock, this.tmpSock]) {
59
+ if (Buffer.byteLength(path) > MAX_SOCKET_PATH_BYTES) {
60
+ throw new Error(`소켓 경로가 너무 길어요(${MAX_SOCKET_PATH_BYTES}바이트 한도): ${path}`);
61
+ }
62
+ }
63
+ ensurePrivateDir(this.options.root);
64
+ await this.clearStaleSocket();
65
+ const state = new PeerState(this.options.dbPath ?? statePath(this.options.root));
66
+ this.state = state;
67
+ try {
68
+ for (const id of state.closeDangling('daemon_restart')) {
69
+ state.audit('share_close', id, 'daemon_restart');
70
+ }
71
+ await this.viewer.start(0);
72
+ await this.listenIpc();
73
+ }
74
+ catch (err) {
75
+ // stop()은 부르지 않는다. 여기까지 연 건 뷰어와 DB뿐이고 stop은 소켓 자리까지
76
+ // 치우는 경로라 반쯤 뜬 데몬이 이미 떠 있는 다른 데몬의 자리를 건드릴 수 있다
77
+ await this.viewer.stop();
78
+ state.close();
79
+ this.state = null;
80
+ throw err;
81
+ }
82
+ this.startedAt = Date.now();
83
+ this.timer = setInterval(() => this.tick(), this.pollMs);
84
+ this.timer.unref();
85
+ }
86
+ async stop() {
87
+ if (this.timer)
88
+ clearInterval(this.timer);
89
+ this.timer = null;
90
+ for (const id of [...this.shares.keys()])
91
+ this.closeShareSafely(id, 'daemon_stop');
92
+ const ipc = this.ipc;
93
+ this.ipc = null;
94
+ try {
95
+ await this.viewer.stop();
96
+ if (ipc) {
97
+ // 열린 연결이 남아 있으면 close 콜백이 안 불려 stop이 끝나지 않는다
98
+ for (const c of this.conns)
99
+ c.destroy();
100
+ await new Promise((resolve) => {
101
+ const timer = setTimeout(resolve, STOP_TIMEOUT_MS);
102
+ ipc.close(() => {
103
+ clearTimeout(timer);
104
+ resolve();
105
+ });
106
+ });
107
+ }
108
+ }
109
+ finally {
110
+ this.removeOwnSocket();
111
+ this.state?.close();
112
+ this.state = null;
113
+ }
114
+ }
115
+ /** 테스트가 타이머를 기다리지 않고 한 번 돌릴 때 쓴다 */
116
+ tick(now = Date.now()) {
117
+ for (const [id, share] of [...this.shares]) {
118
+ try {
119
+ if (now >= share.expiresAt) {
120
+ this.closeShareSafely(id, 'expired');
121
+ continue;
122
+ }
123
+ const before = share.stream.unknownLines;
124
+ const { unknownGrew } = share.stream.poll();
125
+ if (unknownGrew) {
126
+ const added = share.stream.unknownLines - before;
127
+ this.state?.audit('unknown_lines', id, JSON.stringify({ added, claudeVersion: share.stream.claudeVersion ?? null }));
128
+ }
129
+ }
130
+ catch (err) {
131
+ // setInterval 밖으로 던지면 데몬이 죽는다. 그 공유만 종료하고 나머지는 계속 돈다
132
+ process.stderr.write(`[peer] share ${id} failed: ${errMessage(err)}\n`);
133
+ this.closeShareSafely(id, 'error');
134
+ }
135
+ }
136
+ }
137
+ /**
138
+ * closeShare는 DB에 쓰다가 던질 수 있다. tick에서 던지면 뒤 공유를 못 돌고 stop에서
139
+ * 던지면 뷰어와 IPC 서버와 소켓 파일 정리까지 건너뛴다. unshare에서 던지면 공유는 이미
140
+ * 종료됐는데 실패로 답해서 다시 unshare하면 열린 공유가 아니라고 나온다. 공유는 던지기
141
+ * 전에 이미 맵에서 빠지므로 남는 건 DB 기록 하나다.
142
+ */
143
+ closeShareSafely(id, reason) {
144
+ try {
145
+ this.closeShare(id, reason);
146
+ }
147
+ catch (err) {
148
+ process.stderr.write(`[peer] share ${id} close failed: ${errMessage(err)}\n`);
149
+ }
150
+ }
151
+ handle(req) {
152
+ switch (req.op) {
153
+ case 'ping':
154
+ return { ok: true, result: 'pong' };
155
+ case 'status':
156
+ return { ok: true, result: this.status() };
157
+ case 'shares':
158
+ return { ok: true, result: [...this.shares.keys()].map((id) => this.info(id)) };
159
+ case 'share':
160
+ return this.openShare(req);
161
+ case 'unshare': {
162
+ if (typeof req.id !== 'string' || !this.shares.has(req.id)) {
163
+ return { ok: false, error: `열린 공유가 아니에요: ${String(req.id)}` };
164
+ }
165
+ this.closeShareSafely(req.id, 'unshare');
166
+ return { ok: true, result: { id: req.id } };
167
+ }
168
+ default:
169
+ return { ok: false, error: `모르는 요청이에요: ${String(req.op)}` };
170
+ }
171
+ }
172
+ openShare(req) {
173
+ const path = req.transcriptPath;
174
+ if (typeof path !== 'string' || !isAbsolute(path)) {
175
+ return { ok: false, error: 'transcriptPath는 절대경로여야 해요' };
176
+ }
177
+ // 아무 파일이나 열지 못하게 대화 기록 꼴만 받는다
178
+ if (!path.endsWith('.jsonl'))
179
+ return { ok: false, error: '.jsonl 파일만 공유할 수 있어요' };
180
+ let real;
181
+ try {
182
+ real = realpathSync(path);
183
+ }
184
+ catch {
185
+ return { ok: false, error: `대화 기록 파일이 없어요: ${path}` };
186
+ }
187
+ // `x.jsonl -> 다른 파일` 심링크는 이름만 맞는다. 검사와 따라 읽기를 실제 경로에 건다
188
+ if (!real.endsWith('.jsonl'))
189
+ return { ok: false, error: '.jsonl 파일만 공유할 수 있어요' };
190
+ try {
191
+ if (!statSync(real).isFile())
192
+ return { ok: false, error: `파일이 아니에요: ${path}` };
193
+ }
194
+ catch {
195
+ return { ok: false, error: `대화 기록 파일이 없어요: ${path}` };
196
+ }
197
+ if (req.sessionId !== undefined && !isSessionId(req.sessionId)) {
198
+ return { ok: false, error: 'sessionId 형식이 아니에요' };
199
+ }
200
+ const tools = req.tools ?? 'summary';
201
+ if (!isToolsLevel(tools))
202
+ return { ok: false, error: '--tools는 full, summary, none 중 하나예요' };
203
+ const minutes = req.expiresMinutes ?? DEFAULT_EXPIRES_MINUTES;
204
+ if (!Number.isFinite(minutes) || minutes <= 0 || minutes > MAX_EXPIRES_MINUTES) {
205
+ return { ok: false, error: `--expires는 1~${MAX_EXPIRES_MINUTES}분이에요` };
206
+ }
207
+ const id = randomBytes(6).toString('base64url');
208
+ const token = randomBytes(24).toString('base64url');
209
+ const createdAt = Date.now();
210
+ const expiresAt = createdAt + Math.round(minutes * 60_000);
211
+ const stream = new ShareStream({ id, transcriptPath: real, tools, home: this.options.home });
212
+ stream.poll();
213
+ this.shares.set(id, { stream, token, sessionId: req.sessionId ?? null, createdAt, expiresAt });
214
+ this.state.insertShare({
215
+ id,
216
+ sessionId: req.sessionId ?? null,
217
+ transcriptPath: real,
218
+ tools,
219
+ createdAt,
220
+ expiresAt,
221
+ });
222
+ this.state.audit('share_open', id, JSON.stringify({ tools, expiresAt }));
223
+ return { ok: true, result: this.info(id) };
224
+ }
225
+ closeShare(id, reason) {
226
+ const share = this.shares.get(id);
227
+ if (!share)
228
+ return;
229
+ this.shares.delete(id);
230
+ share.stream.close(reason);
231
+ this.state?.closeShare(id, reason);
232
+ this.state?.audit('share_close', id, reason);
233
+ }
234
+ info(id) {
235
+ const s = this.shares.get(id);
236
+ if (!s)
237
+ return undefined;
238
+ return {
239
+ id,
240
+ sessionId: s.sessionId,
241
+ transcriptPath: s.stream.transcriptPath,
242
+ tools: s.stream.tools,
243
+ createdAt: s.createdAt,
244
+ expiresAt: s.expiresAt,
245
+ status: s.stream.currentStatus,
246
+ viewers: s.stream.viewerCount,
247
+ events: s.stream.eventCount,
248
+ unknownLines: s.stream.unknownLines,
249
+ failedLines: s.stream.failedLines,
250
+ oversizedLines: s.stream.oversizedLines,
251
+ droppedEvents: s.stream.droppedEvents,
252
+ title: s.stream.sessionTitle,
253
+ url: `http://127.0.0.1:${this.viewer.port}/s/${id}?t=${s.token}`,
254
+ };
255
+ }
256
+ status() {
257
+ let viewers = 0;
258
+ for (const s of this.shares.values())
259
+ viewers += s.stream.viewerCount;
260
+ return {
261
+ pid: process.pid,
262
+ root: this.options.root,
263
+ viewerPort: this.viewer.port ?? 0,
264
+ startedAt: this.startedAt,
265
+ shares: this.shares.size,
266
+ viewers,
267
+ };
268
+ }
269
+ /**
270
+ * 남은 소켓 파일을 치운다. 누가 받고 있으면 데몬이 이미 떠 있는 거라 던진다.
271
+ * 소켓이 아닌 파일이면 안 지운다 — 경로를 잘못 줬을 때 남의 파일을 지우지 않게.
272
+ *
273
+ * 살아 있는지 본 뒤 지우기 전 사이에 다른 데몬이 새 소켓을 만들면 그걸 지울 수 있다.
274
+ * 지우기 직전에 같은 파일인지 한 번 더 보지만 그 틈까지 막지는 못한다.
275
+ */
276
+ async clearStaleSocket() {
277
+ if (!existsSync(this.sock))
278
+ return;
279
+ const stale = lstatSync(this.sock);
280
+ if (!stale.isSocket()) {
281
+ throw new Error(`소켓 자리에 다른 파일이 있어요: ${this.sock}`);
282
+ }
283
+ const alive = await new Promise((resolve) => {
284
+ const c = createConnection(this.sock);
285
+ c.once('connect', () => {
286
+ c.destroy();
287
+ resolve(true);
288
+ });
289
+ c.once('error', () => resolve(false));
290
+ });
291
+ if (alive)
292
+ throw new Error(`데몬이 이미 떠 있어요: ${this.sock}`);
293
+ if (sameFile(this.sock, stale))
294
+ unlinkSync(this.sock);
295
+ }
296
+ /**
297
+ * 임시 이름으로 listen하고 0600으로 좁힌 뒤 진짜 이름에 하드 링크를 건다.
298
+ *
299
+ * 진짜 이름에 바로 listen하면 net.Server.close가 그 경로를 무조건 지운다(libuv). 그새
300
+ * 다른 데몬이 그 자리를 차지했으면 남의 소켓이 사라진다. 링크는 이름이 이미 있으면
301
+ * 실패하므로 동시에 뜬 데몬끼리 서로 덮어쓰지도 않는다.
302
+ */
303
+ listenIpc() {
304
+ const tmp = this.tmpSock;
305
+ if (existsSync(tmp) && lstatSync(tmp).isSocket())
306
+ unlinkSync(tmp);
307
+ return new Promise((resolve, reject) => {
308
+ const server = createServer((socket) => this.serve(socket));
309
+ server.once('error', reject);
310
+ server.listen(tmp, () => {
311
+ server.off('error', reject);
312
+ server.on('error', (err) => process.stderr.write(`[peer] ipc error: ${err.message}\n`));
313
+ try {
314
+ chmodSync(tmp, 0o600);
315
+ linkSync(tmp, this.sock);
316
+ }
317
+ catch (err) {
318
+ server.close();
319
+ const code = err.code;
320
+ reject(code === 'EEXIST' ? new Error(`데몬이 이미 떠 있어요: ${this.sock}`) : err);
321
+ return;
322
+ }
323
+ try {
324
+ unlinkSync(tmp);
325
+ }
326
+ catch {
327
+ // 남아도 close가 지운다
328
+ }
329
+ const st = lstatSync(this.sock);
330
+ this.ownSocket = { dev: st.dev, ino: st.ino };
331
+ this.ipc = server;
332
+ resolve();
333
+ });
334
+ });
335
+ }
336
+ removeOwnSocket() {
337
+ const own = this.ownSocket;
338
+ this.ownSocket = null;
339
+ if (!own)
340
+ return;
341
+ try {
342
+ if (sameFile(this.sock, own))
343
+ unlinkSync(this.sock);
344
+ }
345
+ catch {
346
+ // 이미 없으면 그만이다
347
+ }
348
+ }
349
+ serve(socket) {
350
+ let buf = '';
351
+ let rejected = false;
352
+ this.conns.add(socket);
353
+ socket.on('close', () => this.conns.delete(socket));
354
+ socket.setEncoding('utf8');
355
+ socket.on('error', () => socket.destroy());
356
+ socket.on('data', (chunk) => {
357
+ if (rejected)
358
+ return;
359
+ buf += chunk;
360
+ if (Buffer.byteLength(buf) > MAX_REQUEST_BYTES) {
361
+ rejected = true;
362
+ buf = '';
363
+ // 바로 destroy하면 거절 답이 나가기 전에 끊길 수 있다
364
+ socket.end(JSON.stringify({ ok: false, error: '요청이 너무 커요' }) + '\n', () => socket.destroy());
365
+ return;
366
+ }
367
+ let nl = buf.indexOf('\n');
368
+ while (nl !== -1) {
369
+ const line = buf.slice(0, nl);
370
+ buf = buf.slice(nl + 1);
371
+ if (line.trim() !== '')
372
+ socket.write(JSON.stringify(this.answer(line)) + '\n');
373
+ nl = buf.indexOf('\n');
374
+ }
375
+ });
376
+ }
377
+ answer(line) {
378
+ let req;
379
+ try {
380
+ req = JSON.parse(line);
381
+ }
382
+ catch {
383
+ return { ok: false, error: 'JSON이 아니에요' };
384
+ }
385
+ if (typeof req !== 'object' ||
386
+ req === null ||
387
+ typeof req.op !== 'string') {
388
+ return { ok: false, error: 'op가 없어요' };
389
+ }
390
+ try {
391
+ return this.handle(req);
392
+ }
393
+ catch (err) {
394
+ return { ok: false, error: errMessage(err) };
395
+ }
396
+ }
397
+ }
398
+ function sameFile(path, id) {
399
+ try {
400
+ const st = lstatSync(path);
401
+ return st.dev === id.dev && st.ino === id.ino;
402
+ }
403
+ catch {
404
+ return false;
405
+ }
406
+ }
407
+ //# sourceMappingURL=daemon.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daemon.js","sourceRoot":"","sources":["../../../src/peer/daemon.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function errMessage(err: unknown): string;
2
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/peer/errors.ts"],"names":[],"mappings":"AAAA,wBAAgB,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAE/C"}
@@ -0,0 +1,4 @@
1
+ export function errMessage(err) {
2
+ return err instanceof Error ? err.message : String(err);
3
+ }
4
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/peer/errors.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,UAAU,CAAC,GAAY;IACrC,OAAO,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AAC1D,CAAC"}
@@ -0,0 +1,14 @@
1
+ export { PeerDaemon } from './daemon.js';
2
+ export type { PeerDaemonOptions } from './daemon.js';
3
+ export { request, DaemonUnavailableError, DAEMON_NOT_RUNNING } from './client.js';
4
+ export { claudeConfigDir, cwdSlug, findSessionByPid, locateTranscript, readSessionFile, } from './locate.js';
5
+ export type { LocateResult, SessionRecord } from './locate.js';
6
+ export { peerRoot, socketPath, statePath } from './paths.js';
7
+ export { redactText, redactValue, truncateBytes, isToolsLevel, REDACTED } from './redact.js';
8
+ export type { ToolsLevel } from './redact.js';
9
+ export { TranscriptTail } from './tail.js';
10
+ export { TranscriptTransformer, stripSystemReminders } from './transform.js';
11
+ export type { PeerEvent } from './transform.js';
12
+ export { PeerState } from './state.js';
13
+ export type { DaemonStatus, PeerRequest, PeerResponse, ShareInfo } from './protocol.js';
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/peer/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAClF,OAAO,EACL,eAAe,EACf,OAAO,EACP,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,GAChB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC7F,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAC7E,YAAY,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,9 @@
1
+ export { PeerDaemon } from './daemon.js';
2
+ export { request, DaemonUnavailableError, DAEMON_NOT_RUNNING } from './client.js';
3
+ export { claudeConfigDir, cwdSlug, findSessionByPid, locateTranscript, readSessionFile, } from './locate.js';
4
+ export { peerRoot, socketPath, statePath } from './paths.js';
5
+ export { redactText, redactValue, truncateBytes, isToolsLevel, REDACTED } from './redact.js';
6
+ export { TranscriptTail } from './tail.js';
7
+ export { TranscriptTransformer, stripSystemReminders } from './transform.js';
8
+ export { PeerState } from './state.js';
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/peer/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAClF,OAAO,EACL,eAAe,EACf,OAAO,EACP,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,GAChB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE7F,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAE7E,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Claude Code 대화 기록 위치 찾기.
3
+ *
4
+ * `sessions/<pid>.json`과 `projects/<슬러그>/<sessionId>.jsonl` 둘 다 문서화되지 않은
5
+ * 형식이다. 그래서 형식이 예상과 다르면 던지지 않고 이유를 담아 돌려준다 — 부르는 쪽이
6
+ * "어디서 무엇을 찾다 못 찾았는지"를 사람에게 그대로 보여줄 수 있어야 한다.
7
+ */
8
+ export type LocateResult = {
9
+ ok: true;
10
+ path: string;
11
+ sessionId: string;
12
+ configDir: string;
13
+ cwd?: string;
14
+ } | {
15
+ ok: false;
16
+ reason: string;
17
+ configDir: string;
18
+ sessionId?: string;
19
+ };
20
+ export interface SessionRecord {
21
+ sessionId: string;
22
+ cwd: string;
23
+ pid?: number;
24
+ }
25
+ /** 설정 디렉토리. Orca 프로필처럼 `CLAUDE_CONFIG_DIR`로 옮겨 둔 경우가 있다 */
26
+ export declare function claudeConfigDir(env?: NodeJS.ProcessEnv): string;
27
+ /**
28
+ * cwd를 `projects/` 아래 디렉토리 이름으로 바꾼다. 실제 이름을 보면 영숫자와 `-`
29
+ * 말고는 전부 `-`가 된다(`/Users/a/.x` → `-Users-a--x`, 한글도 `-`).
30
+ */
31
+ export declare function cwdSlug(cwd: string): string;
32
+ export declare function isSessionId(value: string): boolean;
33
+ /** `sessions/<pid>.json` 하나를 읽는다. 형식이 다르면 null */
34
+ export declare function readSessionFile(path: string): SessionRecord | null;
35
+ /** 부모 pid로 세션을 찾는다. MCP 서버처럼 세션의 자식이 쓴다 */
36
+ export declare function findSessionByPid(pid: number, configDir?: string): SessionRecord | null;
37
+ /**
38
+ * sessionId로 대화 기록 경로를 찾는다.
39
+ *
40
+ * 1. `sessions/*.json`에서 그 세션의 cwd를 찾아 슬러그 경로를 본다
41
+ * 2. 없으면(세션이 끝났거나 슬러그 규칙이 다르면) `projects/*` 아래를 훑는다
42
+ */
43
+ export declare function locateTranscript(sessionId: string, configDir?: string): LocateResult;
44
+ //# sourceMappingURL=locate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locate.d.ts","sourceRoot":"","sources":["../../../src/peer/locate.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AAEH,MAAM,MAAM,YAAY,GACpB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9E;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzE,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,2DAA2D;AAC3D,wBAAgB,eAAe,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAI5E;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE3C;AAKD,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAElD;AAED,kDAAkD;AAClD,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAclE;AAED,2CAA2C;AAC3C,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,SAAoB,GAAG,aAAa,GAAG,IAAI,CAGjG;AA0BD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,SAAoB,GAAG,YAAY,CAoC/F"}
@@ -0,0 +1,116 @@
1
+ import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
2
+ import { homedir } from 'node:os';
3
+ import { isAbsolute, join } from 'node:path';
4
+ /** 설정 디렉토리. Orca 프로필처럼 `CLAUDE_CONFIG_DIR`로 옮겨 둔 경우가 있다 */
5
+ export function claudeConfigDir(env = process.env) {
6
+ const raw = env['CLAUDE_CONFIG_DIR'];
7
+ if (raw && isAbsolute(raw))
8
+ return raw;
9
+ return join(homedir(), '.claude');
10
+ }
11
+ /**
12
+ * cwd를 `projects/` 아래 디렉토리 이름으로 바꾼다. 실제 이름을 보면 영숫자와 `-`
13
+ * 말고는 전부 `-`가 된다(`/Users/a/.x` → `-Users-a--x`, 한글도 `-`).
14
+ */
15
+ export function cwdSlug(cwd) {
16
+ return cwd.replace(/[^A-Za-z0-9-]/g, '-');
17
+ }
18
+ /** sessionId가 경로 조각으로 쓰이므로 `..`이나 `/`가 들어오면 안 된다 */
19
+ const SESSION_ID = /^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$/;
20
+ export function isSessionId(value) {
21
+ return SESSION_ID.test(value);
22
+ }
23
+ /** `sessions/<pid>.json` 하나를 읽는다. 형식이 다르면 null */
24
+ export function readSessionFile(path) {
25
+ let parsed;
26
+ try {
27
+ parsed = JSON.parse(readFileSync(path, 'utf8'));
28
+ }
29
+ catch {
30
+ return null;
31
+ }
32
+ if (typeof parsed !== 'object' || parsed === null)
33
+ return null;
34
+ const rec = parsed;
35
+ const sessionId = rec['sessionId'];
36
+ const cwd = rec['cwd'];
37
+ if (typeof sessionId !== 'string' || typeof cwd !== 'string')
38
+ return null;
39
+ const pid = typeof rec['pid'] === 'number' ? rec['pid'] : undefined;
40
+ return { sessionId, cwd, pid };
41
+ }
42
+ /** 부모 pid로 세션을 찾는다. MCP 서버처럼 세션의 자식이 쓴다 */
43
+ export function findSessionByPid(pid, configDir = claudeConfigDir()) {
44
+ if (!Number.isInteger(pid) || pid <= 0)
45
+ return null;
46
+ return readSessionFile(join(configDir, 'sessions', `${pid}.json`));
47
+ }
48
+ function findSessionById(sessionId, configDir) {
49
+ const dir = join(configDir, 'sessions');
50
+ let names;
51
+ try {
52
+ names = readdirSync(dir);
53
+ }
54
+ catch {
55
+ return null;
56
+ }
57
+ for (const name of names) {
58
+ if (!/^\d+\.json$/.test(name))
59
+ continue;
60
+ const rec = readSessionFile(join(dir, name));
61
+ if (rec?.sessionId === sessionId)
62
+ return rec;
63
+ }
64
+ return null;
65
+ }
66
+ function isFile(path) {
67
+ try {
68
+ return statSync(path).isFile();
69
+ }
70
+ catch {
71
+ return false;
72
+ }
73
+ }
74
+ /**
75
+ * sessionId로 대화 기록 경로를 찾는다.
76
+ *
77
+ * 1. `sessions/*.json`에서 그 세션의 cwd를 찾아 슬러그 경로를 본다
78
+ * 2. 없으면(세션이 끝났거나 슬러그 규칙이 다르면) `projects/*` 아래를 훑는다
79
+ */
80
+ export function locateTranscript(sessionId, configDir = claudeConfigDir()) {
81
+ if (!isSessionId(sessionId)) {
82
+ return { ok: false, reason: 'sessionId 형식이 아니에요', configDir };
83
+ }
84
+ if (!existsSync(configDir)) {
85
+ return { ok: false, reason: '설정 디렉토리가 없어요', configDir, sessionId };
86
+ }
87
+ const session = findSessionById(sessionId, configDir);
88
+ if (session) {
89
+ const bySlug = join(configDir, 'projects', cwdSlug(session.cwd), `${sessionId}.jsonl`);
90
+ if (isFile(bySlug))
91
+ return { ok: true, path: bySlug, sessionId, configDir, cwd: session.cwd };
92
+ }
93
+ const projects = join(configDir, 'projects');
94
+ let dirs;
95
+ try {
96
+ dirs = readdirSync(projects);
97
+ }
98
+ catch {
99
+ return { ok: false, reason: 'projects 디렉토리를 못 읽었어요', configDir, sessionId };
100
+ }
101
+ for (const dir of dirs) {
102
+ const candidate = join(projects, dir, `${sessionId}.jsonl`);
103
+ if (isFile(candidate)) {
104
+ return { ok: true, path: candidate, sessionId, configDir, cwd: session?.cwd };
105
+ }
106
+ }
107
+ return {
108
+ ok: false,
109
+ reason: session
110
+ ? '세션은 있는데 대화 기록 파일을 못 찾았어요'
111
+ : '그 sessionId의 세션도 대화 기록도 못 찾았어요',
112
+ configDir,
113
+ sessionId,
114
+ };
115
+ }
116
+ //# sourceMappingURL=locate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locate.js","sourceRoot":"","sources":["../../../src/peer/locate.ts"],"names":[],"mappings":"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"}