@tienne/gestalt 0.108.0 → 0.110.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +1 -0
- package/dist/package.json +1 -1
- package/dist/src/cli/commands/peer.d.ts +49 -0
- package/dist/src/cli/commands/peer.d.ts.map +1 -0
- package/dist/src/cli/commands/peer.js +302 -0
- package/dist/src/cli/commands/peer.js.map +1 -0
- package/dist/src/cli/index.d.ts.map +1 -1
- package/dist/src/cli/index.js +81 -2
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/peer/client.d.ts +9 -0
- package/dist/src/peer/client.d.ts.map +1 -0
- package/dist/src/peer/client.js +51 -0
- package/dist/src/peer/client.js.map +1 -0
- package/dist/src/peer/daemon.d.ts +83 -0
- package/dist/src/peer/daemon.d.ts.map +1 -0
- package/dist/src/peer/daemon.js +516 -0
- package/dist/src/peer/daemon.js.map +1 -0
- package/dist/src/peer/errors.d.ts +2 -0
- package/dist/src/peer/errors.d.ts.map +1 -0
- package/dist/src/peer/errors.js +4 -0
- package/dist/src/peer/errors.js.map +1 -0
- package/dist/src/peer/feed.d.ts +103 -0
- package/dist/src/peer/feed.d.ts.map +1 -0
- package/dist/src/peer/feed.js +167 -0
- package/dist/src/peer/feed.js.map +1 -0
- package/dist/src/peer/index.d.ts +24 -0
- package/dist/src/peer/index.d.ts.map +1 -0
- package/dist/src/peer/index.js +14 -0
- package/dist/src/peer/index.js.map +1 -0
- package/dist/src/peer/keys.d.ts +26 -0
- package/dist/src/peer/keys.d.ts.map +1 -0
- package/dist/src/peer/keys.js +95 -0
- package/dist/src/peer/keys.js.map +1 -0
- package/dist/src/peer/locate.d.ts +44 -0
- package/dist/src/peer/locate.d.ts.map +1 -0
- package/dist/src/peer/locate.js +116 -0
- package/dist/src/peer/locate.js.map +1 -0
- package/dist/src/peer/lock.d.ts +32 -0
- package/dist/src/peer/lock.d.ts.map +1 -0
- package/dist/src/peer/lock.js +147 -0
- package/dist/src/peer/lock.js.map +1 -0
- package/dist/src/peer/mirror.d.ts +21 -0
- package/dist/src/peer/mirror.d.ts.map +1 -0
- package/dist/src/peer/mirror.js +68 -0
- package/dist/src/peer/mirror.js.map +1 -0
- package/dist/src/peer/network.d.ts +148 -0
- package/dist/src/peer/network.d.ts.map +1 -0
- package/dist/src/peer/network.js +809 -0
- package/dist/src/peer/network.js.map +1 -0
- package/dist/src/peer/paths.d.ts +23 -0
- package/dist/src/peer/paths.d.ts.map +1 -0
- package/dist/src/peer/paths.js +50 -0
- package/dist/src/peer/paths.js.map +1 -0
- package/dist/src/peer/protocol.d.ts +112 -0
- package/dist/src/peer/protocol.d.ts.map +1 -0
- package/dist/src/peer/protocol.js +8 -0
- package/dist/src/peer/protocol.js.map +1 -0
- package/dist/src/peer/redact.d.ts +30 -0
- package/dist/src/peer/redact.d.ts.map +1 -0
- package/dist/src/peer/redact.js +214 -0
- package/dist/src/peer/redact.js.map +1 -0
- package/dist/src/peer/relay.d.ts +70 -0
- package/dist/src/peer/relay.d.ts.map +1 -0
- package/dist/src/peer/relay.js +410 -0
- package/dist/src/peer/relay.js.map +1 -0
- package/dist/src/peer/roster.d.ts +89 -0
- package/dist/src/peer/roster.d.ts.map +1 -0
- package/dist/src/peer/roster.js +160 -0
- package/dist/src/peer/roster.js.map +1 -0
- package/dist/src/peer/seal.d.ts +37 -0
- package/dist/src/peer/seal.d.ts.map +1 -0
- package/dist/src/peer/seal.js +115 -0
- package/dist/src/peer/seal.js.map +1 -0
- package/dist/src/peer/share.d.ts +41 -0
- package/dist/src/peer/share.d.ts.map +1 -0
- package/dist/src/peer/share.js +70 -0
- package/dist/src/peer/share.js.map +1 -0
- package/dist/src/peer/state.d.ts +68 -0
- package/dist/src/peer/state.d.ts.map +1 -0
- package/dist/src/peer/state.js +161 -0
- package/dist/src/peer/state.js.map +1 -0
- package/dist/src/peer/tail.d.ts +55 -0
- package/dist/src/peer/tail.d.ts.map +1 -0
- package/dist/src/peer/tail.js +148 -0
- package/dist/src/peer/tail.js.map +1 -0
- package/dist/src/peer/transform.d.ts +79 -0
- package/dist/src/peer/transform.d.ts.map +1 -0
- package/dist/src/peer/transform.js +237 -0
- package/dist/src/peer/transform.js.map +1 -0
- package/dist/src/peer/transport.d.ts +89 -0
- package/dist/src/peer/transport.d.ts.map +1 -0
- package/dist/src/peer/transport.js +345 -0
- package/dist/src/peer/transport.js.map +1 -0
- package/dist/src/peer/viewer-html.d.ts +10 -0
- package/dist/src/peer/viewer-html.d.ts.map +1 -0
- package/dist/src/peer/viewer-html.js +165 -0
- package/dist/src/peer/viewer-html.js.map +1 -0
- package/dist/src/peer/viewer.d.ts +58 -0
- package/dist/src/peer/viewer.d.ts.map +1 -0
- package/dist/src/peer/viewer.js +249 -0
- package/dist/src/peer/viewer.js.map +1 -0
- package/dist/src/peer/wire.d.ts +90 -0
- package/dist/src/peer/wire.d.ts.map +1 -0
- package/dist/src/peer/wire.js +10 -0
- package/dist/src/peer/wire.js.map +1 -0
- package/dist/src/peer/ws.d.ts +47 -0
- package/dist/src/peer/ws.d.ts.map +1 -0
- package/dist/src/peer/ws.js +308 -0
- package/dist/src/peer/ws.js.map +1 -0
- package/package.json +1 -1
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/.mcp.json +1 -1
- package/plugin/mcp.json +1 -1
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { chmodSync, mkdirSync } from 'node:fs';
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import { dirname } from 'node:path';
|
|
4
|
+
const require = createRequire(import.meta.url);
|
|
5
|
+
function loadSqlite() {
|
|
6
|
+
const mod = require('better-sqlite3');
|
|
7
|
+
if (typeof mod === 'function')
|
|
8
|
+
return mod;
|
|
9
|
+
if (mod.default)
|
|
10
|
+
return mod.default;
|
|
11
|
+
throw new Error('better-sqlite3 did not export a Database constructor');
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* 공유 목록, 팀 설정과 명단, 초대, 감사 로그. 대화 내용은 한 글자도 여기 안 들어온다 —
|
|
15
|
+
* 줄 수나 버전 같은 숫자와 이름만 남긴다. 공유 토큰과 공유 키도 저장하지 않는다. 데몬이
|
|
16
|
+
* 다시 뜨면 이전 공유는 종료된 걸로 치고 새로 연다.
|
|
17
|
+
*
|
|
18
|
+
* 초대 비밀은 저장한다. 관리자 데몬이 나중에 온 join 요청의 증명을 맞춰 봐야 해서다.
|
|
19
|
+
* 파일은 0600이고 쓰고 나면 used_at이 찬다.
|
|
20
|
+
*/
|
|
21
|
+
export class PeerState {
|
|
22
|
+
db;
|
|
23
|
+
constructor(path) {
|
|
24
|
+
mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
|
|
25
|
+
const Database = loadSqlite();
|
|
26
|
+
this.db = new Database(path);
|
|
27
|
+
try {
|
|
28
|
+
chmodSync(path, 0o600);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
// :memory: 같은 경로는 파일이 없다
|
|
32
|
+
}
|
|
33
|
+
this.db.exec(`
|
|
34
|
+
CREATE TABLE IF NOT EXISTS shares (
|
|
35
|
+
id TEXT PRIMARY KEY,
|
|
36
|
+
session_id TEXT,
|
|
37
|
+
transcript_path TEXT NOT NULL,
|
|
38
|
+
tools TEXT NOT NULL,
|
|
39
|
+
created_at INTEGER NOT NULL,
|
|
40
|
+
expires_at INTEGER NOT NULL,
|
|
41
|
+
closed_at INTEGER,
|
|
42
|
+
close_reason TEXT
|
|
43
|
+
);
|
|
44
|
+
CREATE TABLE IF NOT EXISTS kv (
|
|
45
|
+
key TEXT PRIMARY KEY,
|
|
46
|
+
value TEXT NOT NULL
|
|
47
|
+
);
|
|
48
|
+
CREATE TABLE IF NOT EXISTS invites (
|
|
49
|
+
id TEXT PRIMARY KEY,
|
|
50
|
+
secret TEXT NOT NULL,
|
|
51
|
+
person TEXT NOT NULL,
|
|
52
|
+
created_at INTEGER NOT NULL,
|
|
53
|
+
expires_at INTEGER NOT NULL,
|
|
54
|
+
used_at INTEGER,
|
|
55
|
+
used_by TEXT
|
|
56
|
+
);
|
|
57
|
+
CREATE TABLE IF NOT EXISTS audit (
|
|
58
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
59
|
+
at INTEGER NOT NULL,
|
|
60
|
+
share_id TEXT,
|
|
61
|
+
action TEXT NOT NULL,
|
|
62
|
+
detail TEXT
|
|
63
|
+
);
|
|
64
|
+
`);
|
|
65
|
+
}
|
|
66
|
+
insertShare(row) {
|
|
67
|
+
this.db
|
|
68
|
+
.prepare(`INSERT INTO shares (id, session_id, transcript_path, tools, created_at, expires_at)
|
|
69
|
+
VALUES (?, ?, ?, ?, ?, ?)`)
|
|
70
|
+
.run(row.id, row.sessionId, row.transcriptPath, row.tools, row.createdAt, row.expiresAt);
|
|
71
|
+
}
|
|
72
|
+
closeShare(id, reason, at = Date.now()) {
|
|
73
|
+
this.db
|
|
74
|
+
.prepare(`UPDATE shares SET closed_at = ?, close_reason = ? WHERE id = ? AND closed_at IS NULL`)
|
|
75
|
+
.run(at, reason, id);
|
|
76
|
+
}
|
|
77
|
+
/** 데몬이 죽어서 종료 기록 없이 남은 공유를 종료한다. 종료한 id 목록을 돌려준다 */
|
|
78
|
+
closeDangling(reason, at = Date.now()) {
|
|
79
|
+
const rows = this.db.prepare(`SELECT id FROM shares WHERE closed_at IS NULL`).all();
|
|
80
|
+
for (const r of rows)
|
|
81
|
+
this.closeShare(r.id, reason, at);
|
|
82
|
+
return rows.map((r) => r.id);
|
|
83
|
+
}
|
|
84
|
+
getShare(id) {
|
|
85
|
+
const r = this.db.prepare(`SELECT * FROM shares WHERE id = ?`).get(id);
|
|
86
|
+
return r ? toShare(r) : undefined;
|
|
87
|
+
}
|
|
88
|
+
getTeam() {
|
|
89
|
+
return this.getJson('team');
|
|
90
|
+
}
|
|
91
|
+
setTeam(team) {
|
|
92
|
+
this.setJson('team', team);
|
|
93
|
+
}
|
|
94
|
+
/** 받은 명단 중 가장 새것. 받을지는 부르는 쪽이 checkRosterUpdate로 정한 뒤다 */
|
|
95
|
+
getRoster() {
|
|
96
|
+
return this.getJson('roster');
|
|
97
|
+
}
|
|
98
|
+
setRoster(roster) {
|
|
99
|
+
this.setJson('roster', roster);
|
|
100
|
+
}
|
|
101
|
+
insertInvite(row) {
|
|
102
|
+
this.db
|
|
103
|
+
.prepare(`INSERT INTO invites (id, secret, person, created_at, expires_at) VALUES (?, ?, ?, ?, ?)`)
|
|
104
|
+
.run(row.id, row.secret, row.person, row.createdAt, row.expiresAt);
|
|
105
|
+
}
|
|
106
|
+
getInvite(id) {
|
|
107
|
+
const r = this.db.prepare(`SELECT * FROM invites WHERE id = ?`).get(id);
|
|
108
|
+
if (!r)
|
|
109
|
+
return undefined;
|
|
110
|
+
return {
|
|
111
|
+
id: r.id,
|
|
112
|
+
secret: r.secret,
|
|
113
|
+
person: r.person,
|
|
114
|
+
createdAt: r.created_at,
|
|
115
|
+
expiresAt: r.expires_at,
|
|
116
|
+
usedAt: r.used_at,
|
|
117
|
+
usedBy: r.used_by,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
useInvite(id, machineKey, at = Date.now()) {
|
|
121
|
+
this.db
|
|
122
|
+
.prepare(`UPDATE invites SET used_at = ?, used_by = ? WHERE id = ? AND used_at IS NULL`)
|
|
123
|
+
.run(at, machineKey, id);
|
|
124
|
+
}
|
|
125
|
+
getJson(key) {
|
|
126
|
+
const r = this.db.prepare(`SELECT value FROM kv WHERE key = ?`).get(key);
|
|
127
|
+
return r ? JSON.parse(r.value) : null;
|
|
128
|
+
}
|
|
129
|
+
setJson(key, value) {
|
|
130
|
+
this.db
|
|
131
|
+
.prepare(`INSERT INTO kv (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value`)
|
|
132
|
+
.run(key, JSON.stringify(value));
|
|
133
|
+
}
|
|
134
|
+
audit(action, shareId, detail, at = Date.now()) {
|
|
135
|
+
this.db
|
|
136
|
+
.prepare(`INSERT INTO audit (at, share_id, action, detail) VALUES (?, ?, ?, ?)`)
|
|
137
|
+
.run(at, shareId, action, detail ?? null);
|
|
138
|
+
}
|
|
139
|
+
auditLog(shareId) {
|
|
140
|
+
const rows = (shareId
|
|
141
|
+
? this.db.prepare(`SELECT * FROM audit WHERE share_id = ? ORDER BY id`).all(shareId)
|
|
142
|
+
: this.db.prepare(`SELECT * FROM audit ORDER BY id`).all());
|
|
143
|
+
return rows.map((r) => ({ at: r.at, shareId: r.share_id, action: r.action, detail: r.detail }));
|
|
144
|
+
}
|
|
145
|
+
close() {
|
|
146
|
+
this.db.close();
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
function toShare(r) {
|
|
150
|
+
return {
|
|
151
|
+
id: r.id,
|
|
152
|
+
sessionId: r.session_id,
|
|
153
|
+
transcriptPath: r.transcript_path,
|
|
154
|
+
tools: r.tools,
|
|
155
|
+
createdAt: r.created_at,
|
|
156
|
+
expiresAt: r.expires_at,
|
|
157
|
+
closedAt: r.closed_at,
|
|
158
|
+
closeReason: r.close_reason,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../../src/peer/state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export type TailStatus = 'ok' | 'missing' | 'truncated';
|
|
2
|
+
export interface TailRead {
|
|
3
|
+
lines: string[];
|
|
4
|
+
status: TailStatus;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* read 한 번에 읽는 상한. 데몬은 IPC와 뷰어를 같은 스레드에서 돌려서 큰 기록을 한 번에
|
|
8
|
+
* 읽으면 그동안 명령이 멈춘다. 나머지는 다음 read가 이어 읽는다.
|
|
9
|
+
*/
|
|
10
|
+
export declare const DEFAULT_READ_BUDGET_BYTES: number;
|
|
11
|
+
/**
|
|
12
|
+
* 한 줄 상한. 이미지가 든 도구 결과 줄도 들어가게 넉넉히 잡는다. 넘는 줄은 개행까지
|
|
13
|
+
* 버린다. 개행이 끝내 안 오는 파일에서 메모리가 끝없이 늘지 않게 하는 게 목적이다.
|
|
14
|
+
*/
|
|
15
|
+
export declare const DEFAULT_MAX_LINE_BYTES: number;
|
|
16
|
+
export interface TailOptions {
|
|
17
|
+
startOffset?: number;
|
|
18
|
+
readBudgetBytes?: number;
|
|
19
|
+
maxLineBytes?: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* jsonl 파일을 바이트 위치로 이어 읽는다.
|
|
23
|
+
*
|
|
24
|
+
* 줄은 개행이 붙어야 끝난 걸로 본다. Claude Code가 한 줄을 쓰는 도중에 읽으면
|
|
25
|
+
* 반쪽 JSON이 나오는데 그걸 모르는 줄로 세면 숫자가 부풀고 다음 읽기에서 뒷반쪽이
|
|
26
|
+
* 또 깨진다. 개행 없는 꼬리는 다음 읽기까지 들고 있는다.
|
|
27
|
+
*
|
|
28
|
+
* 파일이 줄거나 다른 파일로 바뀌면 멈춘다. 처음부터 다시 읽으면 이미 보낸 줄이
|
|
29
|
+
* 두 번 나간다. 무엇이 바뀌었는지 모르는 채로 계속 흘리는 것보다 멈추고 알리는 게 낫다.
|
|
30
|
+
*/
|
|
31
|
+
export declare class TranscriptTail {
|
|
32
|
+
private readonly path;
|
|
33
|
+
private offset;
|
|
34
|
+
/** 개행을 아직 못 만난 꼬리. 청크마다 합치면 긴 줄에서 누적분을 매번 다시 복사한다 */
|
|
35
|
+
private pending;
|
|
36
|
+
private pendingBytes;
|
|
37
|
+
/** 상한을 넘은 줄의 나머지를 개행까지 버리는 중 */
|
|
38
|
+
private discarding;
|
|
39
|
+
private oversized;
|
|
40
|
+
private inode;
|
|
41
|
+
private stopped;
|
|
42
|
+
private readonly budget;
|
|
43
|
+
private readonly maxLine;
|
|
44
|
+
constructor(path: string, options?: TailOptions);
|
|
45
|
+
/** 다음 읽기가 시작할 바이트 위치. 덜 쓰인 꼬리는 포함하지 않는다 */
|
|
46
|
+
get position(): number;
|
|
47
|
+
/** 상한을 넘어 버린 줄 수. 형식을 몰라 건너뛴 줄과 섞지 않는다 */
|
|
48
|
+
get oversizedLines(): number;
|
|
49
|
+
read(): TailRead;
|
|
50
|
+
/** `buf`는 다음 청크가 덮어쓴다. 들고 있을 꼬리는 복사해 둔다 */
|
|
51
|
+
private feed;
|
|
52
|
+
private dropPending;
|
|
53
|
+
private halt;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=tail.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tail.d.ts","sourceRoot":"","sources":["../../../src/peer/tail.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,SAAS,GAAG,WAAW,CAAC;AAExD,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,EAAE,UAAU,CAAC;CACpB;AAKD;;;GAGG;AACH,eAAO,MAAM,yBAAyB,QAAkB,CAAC;AAEzD;;;GAGG;AACH,eAAO,MAAM,sBAAsB,QAAmB,CAAC;AAEvD,MAAM,WAAW,WAAW;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;GASG;AACH,qBAAa,cAAc;IAcvB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAbvB,OAAO,CAAC,MAAM,CAAS;IACvB,qDAAqD;IACrD,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,YAAY,CAAK;IACzB,gCAAgC;IAChC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,KAAK,CAAqB;IAClC,OAAO,CAAC,OAAO,CAAyB;IACxC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAGd,IAAI,EAAE,MAAM,EAC7B,OAAO,GAAE,WAAgB;IAO3B,2CAA2C;IAC3C,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,0CAA0C;IAC1C,IAAI,cAAc,IAAI,MAAM,CAE3B;IAED,IAAI,IAAI,QAAQ;IA8ChB,2CAA2C;IAC3C,OAAO,CAAC,IAAI;IAkCZ,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,IAAI;CAMb"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { closeSync, fstatSync, openSync, readSync, statSync } from 'node:fs';
|
|
2
|
+
/** 한 번에 읽는 크기. 대화 기록은 수십 MB까지 커서 통째로 올리지 않는다 */
|
|
3
|
+
const CHUNK_BYTES = 1024 * 1024;
|
|
4
|
+
/**
|
|
5
|
+
* read 한 번에 읽는 상한. 데몬은 IPC와 뷰어를 같은 스레드에서 돌려서 큰 기록을 한 번에
|
|
6
|
+
* 읽으면 그동안 명령이 멈춘다. 나머지는 다음 read가 이어 읽는다.
|
|
7
|
+
*/
|
|
8
|
+
export const DEFAULT_READ_BUDGET_BYTES = 4 * 1024 * 1024;
|
|
9
|
+
/**
|
|
10
|
+
* 한 줄 상한. 이미지가 든 도구 결과 줄도 들어가게 넉넉히 잡는다. 넘는 줄은 개행까지
|
|
11
|
+
* 버린다. 개행이 끝내 안 오는 파일에서 메모리가 끝없이 늘지 않게 하는 게 목적이다.
|
|
12
|
+
*/
|
|
13
|
+
export const DEFAULT_MAX_LINE_BYTES = 64 * 1024 * 1024;
|
|
14
|
+
/**
|
|
15
|
+
* jsonl 파일을 바이트 위치로 이어 읽는다.
|
|
16
|
+
*
|
|
17
|
+
* 줄은 개행이 붙어야 끝난 걸로 본다. Claude Code가 한 줄을 쓰는 도중에 읽으면
|
|
18
|
+
* 반쪽 JSON이 나오는데 그걸 모르는 줄로 세면 숫자가 부풀고 다음 읽기에서 뒷반쪽이
|
|
19
|
+
* 또 깨진다. 개행 없는 꼬리는 다음 읽기까지 들고 있는다.
|
|
20
|
+
*
|
|
21
|
+
* 파일이 줄거나 다른 파일로 바뀌면 멈춘다. 처음부터 다시 읽으면 이미 보낸 줄이
|
|
22
|
+
* 두 번 나간다. 무엇이 바뀌었는지 모르는 채로 계속 흘리는 것보다 멈추고 알리는 게 낫다.
|
|
23
|
+
*/
|
|
24
|
+
export class TranscriptTail {
|
|
25
|
+
path;
|
|
26
|
+
offset;
|
|
27
|
+
/** 개행을 아직 못 만난 꼬리. 청크마다 합치면 긴 줄에서 누적분을 매번 다시 복사한다 */
|
|
28
|
+
pending = [];
|
|
29
|
+
pendingBytes = 0;
|
|
30
|
+
/** 상한을 넘은 줄의 나머지를 개행까지 버리는 중 */
|
|
31
|
+
discarding = false;
|
|
32
|
+
oversized = 0;
|
|
33
|
+
inode;
|
|
34
|
+
stopped;
|
|
35
|
+
budget;
|
|
36
|
+
maxLine;
|
|
37
|
+
constructor(path, options = {}) {
|
|
38
|
+
this.path = path;
|
|
39
|
+
this.offset = options.startOffset ?? 0;
|
|
40
|
+
this.budget = options.readBudgetBytes ?? DEFAULT_READ_BUDGET_BYTES;
|
|
41
|
+
this.maxLine = options.maxLineBytes ?? DEFAULT_MAX_LINE_BYTES;
|
|
42
|
+
}
|
|
43
|
+
/** 다음 읽기가 시작할 바이트 위치. 덜 쓰인 꼬리는 포함하지 않는다 */
|
|
44
|
+
get position() {
|
|
45
|
+
return this.offset - this.pendingBytes;
|
|
46
|
+
}
|
|
47
|
+
/** 상한을 넘어 버린 줄 수. 형식을 몰라 건너뛴 줄과 섞지 않는다 */
|
|
48
|
+
get oversizedLines() {
|
|
49
|
+
return this.oversized;
|
|
50
|
+
}
|
|
51
|
+
read() {
|
|
52
|
+
if (this.stopped === 'truncated')
|
|
53
|
+
return { lines: [], status: 'truncated' };
|
|
54
|
+
let size;
|
|
55
|
+
let ino;
|
|
56
|
+
try {
|
|
57
|
+
const st = statSync(this.path);
|
|
58
|
+
size = st.size;
|
|
59
|
+
ino = st.ino;
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return { lines: [], status: 'missing' };
|
|
63
|
+
}
|
|
64
|
+
if (this.inode !== undefined && ino !== this.inode)
|
|
65
|
+
return this.halt();
|
|
66
|
+
if (size < this.offset)
|
|
67
|
+
return this.halt();
|
|
68
|
+
this.inode = ino;
|
|
69
|
+
if (size === this.offset)
|
|
70
|
+
return { lines: [], status: 'ok' };
|
|
71
|
+
let fd;
|
|
72
|
+
try {
|
|
73
|
+
fd = openSync(this.path, 'r');
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
return { lines: [], status: 'missing' };
|
|
77
|
+
}
|
|
78
|
+
const lines = [];
|
|
79
|
+
try {
|
|
80
|
+
// stat과 open 사이에 파일이 바뀌었으면 열린 쪽 기준으로 다시 본다
|
|
81
|
+
const opened = fstatSync(fd);
|
|
82
|
+
if (opened.ino !== this.inode || opened.size < this.offset)
|
|
83
|
+
return this.halt();
|
|
84
|
+
const end = Math.min(opened.size, this.offset + this.budget);
|
|
85
|
+
const chunk = Buffer.alloc(Math.min(CHUNK_BYTES, end - this.offset));
|
|
86
|
+
while (this.offset < end) {
|
|
87
|
+
const want = Math.min(chunk.length, end - this.offset);
|
|
88
|
+
const got = readSync(fd, chunk, 0, want, this.offset);
|
|
89
|
+
if (got <= 0)
|
|
90
|
+
break;
|
|
91
|
+
this.offset += got;
|
|
92
|
+
this.feed(chunk.subarray(0, got), lines);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
finally {
|
|
96
|
+
closeSync(fd);
|
|
97
|
+
}
|
|
98
|
+
return { lines, status: 'ok' };
|
|
99
|
+
}
|
|
100
|
+
/** `buf`는 다음 청크가 덮어쓴다. 들고 있을 꼬리는 복사해 둔다 */
|
|
101
|
+
feed(buf, into) {
|
|
102
|
+
let start = 0;
|
|
103
|
+
while (start < buf.length) {
|
|
104
|
+
const nl = buf.indexOf(0x0a, start);
|
|
105
|
+
if (this.discarding) {
|
|
106
|
+
if (nl === -1)
|
|
107
|
+
return;
|
|
108
|
+
this.discarding = false;
|
|
109
|
+
start = nl + 1;
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
if (nl === -1) {
|
|
113
|
+
const rest = buf.subarray(start);
|
|
114
|
+
if (this.pendingBytes + rest.length > this.maxLine) {
|
|
115
|
+
this.oversized++;
|
|
116
|
+
this.dropPending();
|
|
117
|
+
this.discarding = true;
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
this.pending.push(Buffer.from(rest));
|
|
121
|
+
this.pendingBytes += rest.length;
|
|
122
|
+
}
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const piece = buf.subarray(start, nl);
|
|
126
|
+
if (this.pendingBytes + piece.length > this.maxLine) {
|
|
127
|
+
this.oversized++;
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
const line = this.pendingBytes === 0 ? piece : Buffer.concat([...this.pending, piece]);
|
|
131
|
+
into.push(line.toString('utf8'));
|
|
132
|
+
}
|
|
133
|
+
this.dropPending();
|
|
134
|
+
start = nl + 1;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
dropPending() {
|
|
138
|
+
this.pending = [];
|
|
139
|
+
this.pendingBytes = 0;
|
|
140
|
+
}
|
|
141
|
+
halt() {
|
|
142
|
+
this.stopped = 'truncated';
|
|
143
|
+
this.dropPending();
|
|
144
|
+
this.discarding = false;
|
|
145
|
+
return { lines: [], status: 'truncated' };
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=tail.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tail.js","sourceRoot":"","sources":["../../../src/peer/tail.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { RedactOptions, ToolsLevel } from './redact.js';
|
|
2
|
+
/** 뷰어로 나가는 한 줄. 대화 기록 원문은 이 모양으로만 바깥에 나간다 */
|
|
3
|
+
export type PeerEvent = {
|
|
4
|
+
kind: 'prompt';
|
|
5
|
+
text: string;
|
|
6
|
+
at?: string;
|
|
7
|
+
} | {
|
|
8
|
+
kind: 'reply';
|
|
9
|
+
text: string;
|
|
10
|
+
at?: string;
|
|
11
|
+
} | {
|
|
12
|
+
kind: 'tool_call';
|
|
13
|
+
id: string;
|
|
14
|
+
name: string;
|
|
15
|
+
input?: string;
|
|
16
|
+
at?: string;
|
|
17
|
+
} | {
|
|
18
|
+
kind: 'tool_result';
|
|
19
|
+
toolUseId: string;
|
|
20
|
+
text?: string;
|
|
21
|
+
truncated: boolean;
|
|
22
|
+
hidden: boolean;
|
|
23
|
+
isError: boolean;
|
|
24
|
+
at?: string;
|
|
25
|
+
} | {
|
|
26
|
+
kind: 'title';
|
|
27
|
+
text: string;
|
|
28
|
+
} | {
|
|
29
|
+
kind: 'sidechain';
|
|
30
|
+
at?: string;
|
|
31
|
+
} | {
|
|
32
|
+
kind: 'compacted';
|
|
33
|
+
at?: string;
|
|
34
|
+
};
|
|
35
|
+
/** user 텍스트에서 `<system-reminder>` 블록을 지운다. 닫는 태그가 없으면 끝까지 지운다 */
|
|
36
|
+
export declare function stripSystemReminders(text: string): string;
|
|
37
|
+
export interface TransformOptions extends RedactOptions {
|
|
38
|
+
tools: ToolsLevel;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* 대화 기록 jsonl 한 줄씩 받아 허용 목록에 있는 것만 `PeerEvent`로 바꾼다.
|
|
42
|
+
*
|
|
43
|
+
* 허용 목록이다. 줄 종류든 content 블록 종류든 여기서 명시적으로 꺼내지 않은 건
|
|
44
|
+
* 아무것도 안 나간다. 형식이 바뀌어 새 필드나 새 종류가 생겨도 그대로 새지 않는다.
|
|
45
|
+
*
|
|
46
|
+
* 상태가 있다 — 서브에이전트 줄이 이어지면 표시를 한 번만 낸다.
|
|
47
|
+
*/
|
|
48
|
+
export declare class TranscriptTransformer {
|
|
49
|
+
private readonly options;
|
|
50
|
+
private inSidechain;
|
|
51
|
+
private unknown;
|
|
52
|
+
private failed;
|
|
53
|
+
private claudeVersion;
|
|
54
|
+
constructor(options: TransformOptions);
|
|
55
|
+
/** 모르는 줄 종류와 JSON으로 안 읽힌 줄을 합친 수 */
|
|
56
|
+
get unknownLines(): number;
|
|
57
|
+
/**
|
|
58
|
+
* 바꾸다 예외가 난 줄 수. 모르는 줄과 따로 센다. 모르는 줄은 형식이 바뀐 신호라 감사
|
|
59
|
+
* 로그에 버전과 함께 남기는데 여기에 섞이면 그 신호가 흐려진다.
|
|
60
|
+
*/
|
|
61
|
+
get failedLines(): number;
|
|
62
|
+
/** 마지막으로 본 Claude Code 버전. 모르는 줄이 생겼을 때 감사 로그에 남긴다 */
|
|
63
|
+
get version(): string | undefined;
|
|
64
|
+
/**
|
|
65
|
+
* 한 줄을 바꾼다. 줄 하나에서 난 예외는 여기서 접고 그 줄만 버린다. 2만 단계로
|
|
66
|
+
* 중첩된 도구 입력이 가리기 재귀에서 스택을 넘기는 걸 봤다. 던지게 두면 이 공유의
|
|
67
|
+
* 나머지 줄을 더 못 읽는다. 읽던 중이면 tick이 그 공유를 error로 종료하고 공유를 여는
|
|
68
|
+
* 첫 poll이면 share 요청이 실패한다.
|
|
69
|
+
*/
|
|
70
|
+
push(line: string): PeerEvent[];
|
|
71
|
+
private parse;
|
|
72
|
+
private fromUser;
|
|
73
|
+
private fromAssistant;
|
|
74
|
+
private prompt;
|
|
75
|
+
private toolCall;
|
|
76
|
+
private toolResult;
|
|
77
|
+
private redact;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=transform.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../../src/peer/transform.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE7D,6CAA6C;AAC7C,MAAM,MAAM,SAAS,GACjB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,GAC5C;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,GAC5E;IACE,IAAI,EAAE,aAAa,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,EAAE,CAAC,EAAE,MAAM,CAAC;CACb,GACD;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC/B;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AA6BvC,iEAAiE;AACjE,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,MAAM,WAAW,gBAAiB,SAAQ,aAAa;IACrD,KAAK,EAAE,UAAU,CAAC;CACnB;AAED;;;;;;;GAOG;AACH,qBAAa,qBAAqB;IAMpB,OAAO,CAAC,QAAQ,CAAC,OAAO;IALpC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,aAAa,CAAqB;gBAEb,OAAO,EAAE,gBAAgB;IAEtD,oCAAoC;IACpC,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED;;;OAGG;IACH,IAAI,WAAW,IAAI,MAAM,CAExB;IAED,sDAAsD;IACtD,IAAI,OAAO,IAAI,MAAM,GAAG,SAAS,CAEhC;IAED;;;;;OAKG;IACH,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE;IAS/B,OAAO,CAAC,KAAK;IAmDb,OAAO,CAAC,QAAQ;IAgBhB,OAAO,CAAC,aAAa;IAqBrB,OAAO,CAAC,MAAM;IAKd,OAAO,CAAC,QAAQ;IAYhB,OAAO,CAAC,UAAU;IA+BlB,OAAO,CAAC,MAAM;CAGf"}
|