@tienne/gestalt 0.107.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.
- package/CLAUDE.md +2 -0
- package/README.ko.md +1 -0
- package/README.md +1 -0
- package/dist/package.json +1 -1
- package/dist/plugin/role-agents/lens-context/AGENT.md +94 -0
- package/dist/plugin/role-agents/lens-link/AGENT.md +83 -0
- package/dist/plugin/role-agents/lens-reader/AGENT.md +230 -0
- package/dist/plugin/skills/_shared/proactive-routing.md +1 -0
- package/dist/plugin/skills/lens/SKILL.md +375 -0
- package/dist/schemas/gestalt.schema.json +13 -0
- package/dist/src/cli/commands/digest.d.ts +2 -0
- package/dist/src/cli/commands/digest.d.ts.map +1 -1
- package/dist/src/cli/commands/digest.js +6 -0
- package/dist/src/cli/commands/digest.js.map +1 -1
- package/dist/src/cli/commands/lens.d.ts +27 -0
- package/dist/src/cli/commands/lens.d.ts.map +1 -0
- package/dist/src/cli/commands/lens.js +200 -0
- package/dist/src/cli/commands/lens.js.map +1 -0
- package/dist/src/cli/commands/peer.d.ts +19 -0
- package/dist/src/cli/commands/peer.d.ts.map +1 -0
- package/dist/src/cli/commands/peer.js +147 -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 +72 -2
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/digest/format.d.ts.map +1 -1
- package/dist/src/digest/format.js +1 -0
- package/dist/src/digest/format.js.map +1 -1
- package/dist/src/digest/frames.d.ts.map +1 -1
- package/dist/src/digest/frames.js +1 -1
- package/dist/src/digest/frames.js.map +1 -1
- package/dist/src/digest/ingest.d.ts +8 -1
- package/dist/src/digest/ingest.d.ts.map +1 -1
- package/dist/src/digest/ingest.js +2 -1
- package/dist/src/digest/ingest.js.map +1 -1
- package/dist/src/digest/lens-schema.d.ts +542 -0
- package/dist/src/digest/lens-schema.d.ts.map +1 -0
- package/dist/src/digest/lens-schema.js +108 -0
- package/dist/src/digest/lens-schema.js.map +1 -0
- package/dist/src/digest/lens-source.d.ts +260 -0
- package/dist/src/digest/lens-source.d.ts.map +1 -0
- package/dist/src/digest/lens-source.js +92 -0
- package/dist/src/digest/lens-source.js.map +1 -0
- package/dist/src/digest/lens-widget-schema.d.ts +1225 -0
- package/dist/src/digest/lens-widget-schema.d.ts.map +1 -0
- package/dist/src/digest/lens-widget-schema.js +80 -0
- package/dist/src/digest/lens-widget-schema.js.map +1 -0
- package/dist/src/digest/lens-widgets.d.ts +25 -0
- package/dist/src/digest/lens-widgets.d.ts.map +1 -0
- package/dist/src/digest/lens-widgets.js +225 -0
- package/dist/src/digest/lens-widgets.js.map +1 -0
- package/dist/src/digest/lint-lens-context.d.ts +102 -0
- package/dist/src/digest/lint-lens-context.d.ts.map +1 -0
- package/dist/src/digest/lint-lens-context.js +192 -0
- package/dist/src/digest/lint-lens-context.js.map +1 -0
- package/dist/src/digest/lint-lens.d.ts +17 -0
- package/dist/src/digest/lint-lens.d.ts.map +1 -0
- package/dist/src/digest/lint-lens.js +237 -0
- package/dist/src/digest/lint-lens.js.map +1 -0
- package/dist/src/digest/lint.d.ts +14 -0
- package/dist/src/digest/lint.d.ts.map +1 -1
- package/dist/src/digest/lint.js +156 -2
- package/dist/src/digest/lint.js.map +1 -1
- package/dist/src/digest/merge.d.ts.map +1 -1
- package/dist/src/digest/merge.js +11 -2
- package/dist/src/digest/merge.js.map +1 -1
- package/dist/src/digest/prose.d.ts.map +1 -1
- package/dist/src/digest/prose.js +8 -0
- package/dist/src/digest/prose.js.map +1 -1
- package/dist/src/digest/render-html.d.ts +5 -0
- package/dist/src/digest/render-html.d.ts.map +1 -1
- package/dist/src/digest/render-html.js +93 -18
- package/dist/src/digest/render-html.js.map +1 -1
- package/dist/src/digest/render-lens.d.ts +61 -0
- package/dist/src/digest/render-lens.d.ts.map +1 -0
- package/dist/src/digest/render-lens.js +273 -0
- package/dist/src/digest/render-lens.js.map +1 -0
- package/dist/src/digest/render-md.d.ts +5 -0
- package/dist/src/digest/render-md.d.ts.map +1 -1
- package/dist/src/digest/render-md.js +116 -7
- package/dist/src/digest/render-md.js.map +1 -1
- package/dist/src/digest/render-widgets.d.ts +13 -0
- package/dist/src/digest/render-widgets.d.ts.map +1 -0
- package/dist/src/digest/render-widgets.js +197 -0
- package/dist/src/digest/render-widgets.js.map +1 -0
- package/dist/src/digest/render.d.ts +2 -0
- package/dist/src/digest/render.d.ts.map +1 -1
- package/dist/src/digest/render.js +17 -3
- package/dist/src/digest/render.js.map +1 -1
- package/dist/src/digest/schema.d.ts +14683 -2022
- package/dist/src/digest/schema.d.ts.map +1 -1
- package/dist/src/digest/schema.js +67 -6
- package/dist/src/digest/schema.js.map +1 -1
- package/dist/src/digest/server.d.ts +2 -1
- package/dist/src/digest/server.d.ts.map +1 -1
- package/dist/src/digest/server.js +26 -11
- package/dist/src/digest/server.js.map +1 -1
- package/dist/src/digest/viewer-js.d.ts.map +1 -1
- package/dist/src/digest/viewer-js.js +120 -4
- package/dist/src/digest/viewer-js.js.map +1 -1
- package/dist/src/lens/attach.d.ts +436 -0
- package/dist/src/lens/attach.d.ts.map +1 -0
- package/dist/src/lens/attach.js +46 -0
- package/dist/src/lens/attach.js.map +1 -0
- package/dist/src/lens/ingest.d.ts +75 -0
- package/dist/src/lens/ingest.d.ts.map +1 -0
- package/dist/src/lens/ingest.js +558 -0
- package/dist/src/lens/ingest.js.map +1 -0
- package/dist/src/lens/kind.d.ts +11 -0
- package/dist/src/lens/kind.d.ts.map +1 -0
- package/dist/src/lens/kind.js +59 -0
- package/dist/src/lens/kind.js.map +1 -0
- package/dist/src/lens/knowledge.d.ts +53 -0
- package/dist/src/lens/knowledge.d.ts.map +1 -0
- package/dist/src/lens/knowledge.js +202 -0
- package/dist/src/lens/knowledge.js.map +1 -0
- package/dist/src/lens/notes.d.ts +73 -0
- package/dist/src/lens/notes.d.ts.map +1 -0
- package/dist/src/lens/notes.js +276 -0
- package/dist/src/lens/notes.js.map +1 -0
- package/dist/src/lens/panels.d.ts +10 -0
- package/dist/src/lens/panels.d.ts.map +1 -0
- package/dist/src/lens/panels.js +25 -0
- package/dist/src/lens/panels.js.map +1 -0
- package/dist/src/lens/pdf-extract-py.d.ts +15 -0
- package/dist/src/lens/pdf-extract-py.d.ts.map +1 -0
- package/dist/src/lens/pdf-extract-py.js +414 -0
- package/dist/src/lens/pdf-extract-py.js.map +1 -0
- package/dist/src/lens/podcast.d.ts +36 -0
- package/dist/src/lens/podcast.d.ts.map +1 -0
- package/dist/src/lens/podcast.js +104 -0
- package/dist/src/lens/podcast.js.map +1 -0
- package/dist/src/lens/python.d.ts +33 -0
- package/dist/src/lens/python.d.ts.map +1 -0
- package/dist/src/lens/python.js +61 -0
- package/dist/src/lens/python.js.map +1 -0
- package/dist/src/lens/web-extract-py.d.ts +9 -0
- package/dist/src/lens/web-extract-py.d.ts.map +1 -0
- package/dist/src/lens/web-extract-py.js +114 -0
- package/dist/src/lens/web-extract-py.js.map +1 -0
- package/dist/src/mcp/schemas.d.ts +3 -0
- package/dist/src/mcp/schemas.d.ts.map +1 -1
- package/dist/src/mcp/schemas.js +4 -0
- package/dist/src/mcp/schemas.js.map +1 -1
- package/dist/src/mcp/server.js +1 -1
- package/dist/src/mcp/server.js.map +1 -1
- package/dist/src/mcp/tools/digest-passthrough.d.ts.map +1 -1
- package/dist/src/mcp/tools/digest-passthrough.js +5 -0
- package/dist/src/mcp/tools/digest-passthrough.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 +71 -0
- package/dist/src/peer/daemon.d.ts.map +1 -0
- package/dist/src/peer/daemon.js +407 -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/index.d.ts +14 -0
- package/dist/src/peer/index.d.ts.map +1 -0
- package/dist/src/peer/index.js +9 -0
- package/dist/src/peer/index.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/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 +61 -0
- package/dist/src/peer/protocol.d.ts.map +1 -0
- package/dist/src/peer/protocol.js +7 -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/share.d.ts +123 -0
- package/dist/src/peer/share.d.ts.map +1 -0
- package/dist/src/peer/share.js +204 -0
- package/dist/src/peer/share.js.map +1 -0
- package/dist/src/peer/state.d.ts +37 -0
- package/dist/src/peer/state.d.ts.map +1 -0
- package/dist/src/peer/state.js +99 -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/viewer-html.d.ts +10 -0
- package/dist/src/peer/viewer-html.d.ts.map +1 -0
- package/dist/src/peer/viewer-html.js +157 -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/research/source-create.d.ts +6 -1
- package/dist/src/research/source-create.d.ts.map +1 -1
- package/dist/src/research/source-create.js +41 -10
- package/dist/src/research/source-create.js.map +1 -1
- 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
- package/plugin/role-agents/lens-context/AGENT.md +94 -0
- package/plugin/role-agents/lens-link/AGENT.md +83 -0
- package/plugin/role-agents/lens-reader/AGENT.md +230 -0
- package/plugin/skills/_shared/proactive-routing.md +1 -0
- package/plugin/skills/lens/SKILL.md +375 -0
- package/schemas/gestalt.schema.json +13 -0
|
@@ -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"}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import { redactText, redactValue, truncateBytes, TOOL_RESULT_SUMMARY_BYTES } from './redact.js';
|
|
2
|
+
/** `tool_use` 입력 요약 길이. 결과보다 짧게 둔다 — 입력은 접힌 줄 제목처럼 읽힌다 */
|
|
3
|
+
const TOOL_INPUT_SUMMARY_BYTES = 1024;
|
|
4
|
+
/**
|
|
5
|
+
* 내용을 안 보내는 줄 종류. 2.1.311 기록에서 본 것들이다. 여기 있는 건 조용히
|
|
6
|
+
* 버리고 여기에도 허용 목록에도 없는 종류만 "모르는 줄"로 센다.
|
|
7
|
+
*
|
|
8
|
+
* 이 목록은 차단 목록이 아니다. 지워도 새는 게 없고 "모르는 줄" 숫자만 는다.
|
|
9
|
+
*/
|
|
10
|
+
const KNOWN_DROPPED = new Set([
|
|
11
|
+
'api-request',
|
|
12
|
+
'api-request-blob',
|
|
13
|
+
'api-request-shape',
|
|
14
|
+
'attachment',
|
|
15
|
+
'system',
|
|
16
|
+
'last-prompt',
|
|
17
|
+
'queue-operation',
|
|
18
|
+
'tools-used',
|
|
19
|
+
'cost-state',
|
|
20
|
+
'mode',
|
|
21
|
+
'atis-latch',
|
|
22
|
+
'summary',
|
|
23
|
+
'file-history-snapshot',
|
|
24
|
+
]);
|
|
25
|
+
const SYSTEM_REMINDER = /<system-reminder>[\s\S]*?(?:<\/system-reminder>|$)/g;
|
|
26
|
+
/** user 텍스트에서 `<system-reminder>` 블록을 지운다. 닫는 태그가 없으면 끝까지 지운다 */
|
|
27
|
+
export function stripSystemReminders(text) {
|
|
28
|
+
return text.replace(SYSTEM_REMINDER, '').trim();
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 대화 기록 jsonl 한 줄씩 받아 허용 목록에 있는 것만 `PeerEvent`로 바꾼다.
|
|
32
|
+
*
|
|
33
|
+
* 허용 목록이다. 줄 종류든 content 블록 종류든 여기서 명시적으로 꺼내지 않은 건
|
|
34
|
+
* 아무것도 안 나간다. 형식이 바뀌어 새 필드나 새 종류가 생겨도 그대로 새지 않는다.
|
|
35
|
+
*
|
|
36
|
+
* 상태가 있다 — 서브에이전트 줄이 이어지면 표시를 한 번만 낸다.
|
|
37
|
+
*/
|
|
38
|
+
export class TranscriptTransformer {
|
|
39
|
+
options;
|
|
40
|
+
inSidechain = false;
|
|
41
|
+
unknown = 0;
|
|
42
|
+
failed = 0;
|
|
43
|
+
claudeVersion;
|
|
44
|
+
constructor(options) {
|
|
45
|
+
this.options = options;
|
|
46
|
+
}
|
|
47
|
+
/** 모르는 줄 종류와 JSON으로 안 읽힌 줄을 합친 수 */
|
|
48
|
+
get unknownLines() {
|
|
49
|
+
return this.unknown;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* 바꾸다 예외가 난 줄 수. 모르는 줄과 따로 센다. 모르는 줄은 형식이 바뀐 신호라 감사
|
|
53
|
+
* 로그에 버전과 함께 남기는데 여기에 섞이면 그 신호가 흐려진다.
|
|
54
|
+
*/
|
|
55
|
+
get failedLines() {
|
|
56
|
+
return this.failed;
|
|
57
|
+
}
|
|
58
|
+
/** 마지막으로 본 Claude Code 버전. 모르는 줄이 생겼을 때 감사 로그에 남긴다 */
|
|
59
|
+
get version() {
|
|
60
|
+
return this.claudeVersion;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* 한 줄을 바꾼다. 줄 하나에서 난 예외는 여기서 접고 그 줄만 버린다. 2만 단계로
|
|
64
|
+
* 중첩된 도구 입력이 가리기 재귀에서 스택을 넘기는 걸 봤다. 던지게 두면 이 공유의
|
|
65
|
+
* 나머지 줄을 더 못 읽는다. 읽던 중이면 tick이 그 공유를 error로 종료하고 공유를 여는
|
|
66
|
+
* 첫 poll이면 share 요청이 실패한다.
|
|
67
|
+
*/
|
|
68
|
+
push(line) {
|
|
69
|
+
try {
|
|
70
|
+
return this.parse(line);
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
this.failed++;
|
|
74
|
+
return [];
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
parse(line) {
|
|
78
|
+
const trimmed = line.trim();
|
|
79
|
+
if (trimmed === '')
|
|
80
|
+
return [];
|
|
81
|
+
let parsed;
|
|
82
|
+
try {
|
|
83
|
+
parsed = JSON.parse(trimmed);
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
this.unknown++;
|
|
87
|
+
return [];
|
|
88
|
+
}
|
|
89
|
+
if (!isRecord(parsed) || typeof parsed['type'] !== 'string') {
|
|
90
|
+
this.unknown++;
|
|
91
|
+
return [];
|
|
92
|
+
}
|
|
93
|
+
if (typeof parsed['version'] === 'string')
|
|
94
|
+
this.claudeVersion = parsed['version'];
|
|
95
|
+
const type = parsed['type'];
|
|
96
|
+
const at = typeof parsed['timestamp'] === 'string' ? parsed['timestamp'] : undefined;
|
|
97
|
+
if (type === 'ai-title') {
|
|
98
|
+
const title = parsed['aiTitle'];
|
|
99
|
+
return typeof title === 'string' && title.trim() !== ''
|
|
100
|
+
? [{ kind: 'title', text: this.redact(title) }]
|
|
101
|
+
: [];
|
|
102
|
+
}
|
|
103
|
+
if (type !== 'user' && type !== 'assistant') {
|
|
104
|
+
if (!KNOWN_DROPPED.has(type))
|
|
105
|
+
this.unknown++;
|
|
106
|
+
return [];
|
|
107
|
+
}
|
|
108
|
+
if (parsed['isSidechain'] === true) {
|
|
109
|
+
if (this.inSidechain)
|
|
110
|
+
return [];
|
|
111
|
+
this.inSidechain = true;
|
|
112
|
+
return [{ kind: 'sidechain', at }];
|
|
113
|
+
}
|
|
114
|
+
this.inSidechain = false;
|
|
115
|
+
// 하네스가 끼워 넣은 줄이다. 주인이 친 말이 아니고 CLAUDE.md나 명령 출력이 들어 있다
|
|
116
|
+
if (parsed['isMeta'] === true)
|
|
117
|
+
return [];
|
|
118
|
+
// 압축 요약은 지난 대화 전체를 다시 적은 글이라 그 안에 무엇이 섞였는지 모른다
|
|
119
|
+
if (parsed['isCompactSummary'] === true)
|
|
120
|
+
return [{ kind: 'compacted', at }];
|
|
121
|
+
const message = parsed['message'];
|
|
122
|
+
if (!isRecord(message))
|
|
123
|
+
return [];
|
|
124
|
+
const content = message['content'];
|
|
125
|
+
return type === 'user' ? this.fromUser(content, at) : this.fromAssistant(content, at);
|
|
126
|
+
}
|
|
127
|
+
fromUser(content, at) {
|
|
128
|
+
if (typeof content === 'string')
|
|
129
|
+
return this.prompt(content, at);
|
|
130
|
+
if (!Array.isArray(content))
|
|
131
|
+
return [];
|
|
132
|
+
const events = [];
|
|
133
|
+
for (const block of content) {
|
|
134
|
+
if (!isRecord(block))
|
|
135
|
+
continue;
|
|
136
|
+
if (block['type'] === 'text' && typeof block['text'] === 'string') {
|
|
137
|
+
events.push(...this.prompt(block['text'], at));
|
|
138
|
+
}
|
|
139
|
+
else if (block['type'] === 'tool_result') {
|
|
140
|
+
events.push(this.toolResult(block, at));
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return events;
|
|
144
|
+
}
|
|
145
|
+
fromAssistant(content, at) {
|
|
146
|
+
if (typeof content === 'string') {
|
|
147
|
+
const text = this.redact(content).trim();
|
|
148
|
+
return text === '' ? [] : [{ kind: 'reply', text, at }];
|
|
149
|
+
}
|
|
150
|
+
if (!Array.isArray(content))
|
|
151
|
+
return [];
|
|
152
|
+
const events = [];
|
|
153
|
+
for (const block of content) {
|
|
154
|
+
if (!isRecord(block))
|
|
155
|
+
continue;
|
|
156
|
+
if (block['type'] === 'text' && typeof block['text'] === 'string') {
|
|
157
|
+
const text = this.redact(block['text']).trim();
|
|
158
|
+
if (text !== '')
|
|
159
|
+
events.push({ kind: 'reply', text, at });
|
|
160
|
+
}
|
|
161
|
+
else if (block['type'] === 'tool_use') {
|
|
162
|
+
events.push(this.toolCall(block, at));
|
|
163
|
+
}
|
|
164
|
+
// thinking, redacted_thinking, server_tool_use 등은 꺼내지 않는다
|
|
165
|
+
}
|
|
166
|
+
return events;
|
|
167
|
+
}
|
|
168
|
+
prompt(raw, at) {
|
|
169
|
+
const text = this.redact(stripSystemReminders(raw));
|
|
170
|
+
return text === '' ? [] : [{ kind: 'prompt', text, at }];
|
|
171
|
+
}
|
|
172
|
+
toolCall(block, at) {
|
|
173
|
+
const id = typeof block['id'] === 'string' ? block['id'] : '';
|
|
174
|
+
const name = typeof block['name'] === 'string' ? this.redact(block['name']) : '(이름 없음)';
|
|
175
|
+
if (this.options.tools === 'none')
|
|
176
|
+
return { kind: 'tool_call', id, name, at };
|
|
177
|
+
const redacted = redactValue(block['input'] ?? {}, this.options);
|
|
178
|
+
const json = JSON.stringify(redacted) ?? '';
|
|
179
|
+
const input = this.options.tools === 'full' ? json : truncateBytes(json, TOOL_INPUT_SUMMARY_BYTES).text;
|
|
180
|
+
return { kind: 'tool_call', id, name, input, at };
|
|
181
|
+
}
|
|
182
|
+
toolResult(block, at) {
|
|
183
|
+
const toolUseId = typeof block['tool_use_id'] === 'string' ? block['tool_use_id'] : '';
|
|
184
|
+
const isError = block['is_error'] === true;
|
|
185
|
+
if (this.options.tools === 'none') {
|
|
186
|
+
return { kind: 'tool_result', toolUseId, truncated: false, hidden: true, isError, at };
|
|
187
|
+
}
|
|
188
|
+
const full = this.redact(resultText(block['content']));
|
|
189
|
+
if (this.options.tools === 'full') {
|
|
190
|
+
return {
|
|
191
|
+
kind: 'tool_result',
|
|
192
|
+
toolUseId,
|
|
193
|
+
text: full,
|
|
194
|
+
truncated: false,
|
|
195
|
+
hidden: false,
|
|
196
|
+
isError,
|
|
197
|
+
at,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
const cut = truncateBytes(full, TOOL_RESULT_SUMMARY_BYTES);
|
|
201
|
+
return {
|
|
202
|
+
kind: 'tool_result',
|
|
203
|
+
toolUseId,
|
|
204
|
+
text: cut.text,
|
|
205
|
+
truncated: cut.truncated,
|
|
206
|
+
hidden: false,
|
|
207
|
+
isError,
|
|
208
|
+
at,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
redact(text) {
|
|
212
|
+
return redactText(text, this.options);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
/** tool_result의 content는 문자열이거나 블록 배열이다. 텍스트 블록만 꺼낸다 */
|
|
216
|
+
function resultText(content) {
|
|
217
|
+
if (typeof content === 'string')
|
|
218
|
+
return stripSystemReminders(content);
|
|
219
|
+
if (!Array.isArray(content))
|
|
220
|
+
return '';
|
|
221
|
+
const parts = [];
|
|
222
|
+
for (const block of content) {
|
|
223
|
+
if (!isRecord(block))
|
|
224
|
+
continue;
|
|
225
|
+
if (block['type'] === 'text' && typeof block['text'] === 'string') {
|
|
226
|
+
parts.push(stripSystemReminders(block['text']));
|
|
227
|
+
}
|
|
228
|
+
else if (block['type'] === 'image') {
|
|
229
|
+
parts.push('[이미지]');
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return parts.join('\n');
|
|
233
|
+
}
|
|
234
|
+
function isRecord(value) {
|
|
235
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
236
|
+
}
|
|
237
|
+
//# sourceMappingURL=transform.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transform.js","sourceRoot":"","sources":["../../../src/peer/transform.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const VIEWER_WARNING = "\uBE44\uBC00\uAC12 \uD328\uD134\uC740 \uAC00\uB9AC\uC9C0\uB9CC \uC804\uBD80 \uC7A1\uC9C0\uB294 \uBABB\uD574\uC694.";
|
|
2
|
+
/**
|
|
3
|
+
* 뷰어 페이지. 바깥 자원을 하나도 안 끌어온다 — CSP가 `default-src 'none'`이라
|
|
4
|
+
* 인라인 스크립트와 스타일도 nonce가 맞는 것만 돈다.
|
|
5
|
+
*
|
|
6
|
+
* 대화 내용은 전부 textContent로 넣는다. 마크다운을 HTML로 그리면 남의 도구 출력에
|
|
7
|
+
* 든 태그가 이 페이지에서 실행될 길이 생긴다. localStorage나 IndexedDB도 안 쓴다.
|
|
8
|
+
*/
|
|
9
|
+
export declare function renderViewerHtml(nonce: string, maxViewers: number): string;
|
|
10
|
+
//# sourceMappingURL=viewer-html.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"viewer-html.d.ts","sourceRoot":"","sources":["../../../src/peer/viewer-html.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc,uHAA6B,CAAC;AAEzD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAmJ1E"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
export const VIEWER_WARNING = '비밀값 패턴은 가리지만 전부 잡지는 못해요.';
|
|
2
|
+
/**
|
|
3
|
+
* 뷰어 페이지. 바깥 자원을 하나도 안 끌어온다 — CSP가 `default-src 'none'`이라
|
|
4
|
+
* 인라인 스크립트와 스타일도 nonce가 맞는 것만 돈다.
|
|
5
|
+
*
|
|
6
|
+
* 대화 내용은 전부 textContent로 넣는다. 마크다운을 HTML로 그리면 남의 도구 출력에
|
|
7
|
+
* 든 태그가 이 페이지에서 실행될 길이 생긴다. localStorage나 IndexedDB도 안 쓴다.
|
|
8
|
+
*/
|
|
9
|
+
export function renderViewerHtml(nonce, maxViewers) {
|
|
10
|
+
return `<!doctype html>
|
|
11
|
+
<html lang="ko">
|
|
12
|
+
<head>
|
|
13
|
+
<meta charset="utf-8">
|
|
14
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
15
|
+
<meta name="referrer" content="no-referrer">
|
|
16
|
+
<title>gestalt peer</title>
|
|
17
|
+
<style nonce="${nonce}">
|
|
18
|
+
:root { color-scheme: light dark; --muted: #888; --line: #8884; }
|
|
19
|
+
body { font: 14px/1.55 -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; margin: 0; }
|
|
20
|
+
header { position: sticky; top: 0; padding: 10px 16px; border-bottom: 1px solid var(--line);
|
|
21
|
+
background: Canvas; z-index: 1; }
|
|
22
|
+
header h1 { font-size: 15px; margin: 0 0 4px; }
|
|
23
|
+
.warn { color: #b45309; font-size: 13px; }
|
|
24
|
+
.meta { color: var(--muted); font-size: 12px; display: flex; gap: 12px; flex-wrap: wrap; }
|
|
25
|
+
main { padding: 12px 16px 48px; max-width: 980px; }
|
|
26
|
+
.ev { margin: 10px 0; }
|
|
27
|
+
.who { font-size: 12px; color: var(--muted); }
|
|
28
|
+
.text { white-space: pre-wrap; word-break: break-word; }
|
|
29
|
+
.prompt .text { border-left: 3px solid #2563eb; padding-left: 8px; }
|
|
30
|
+
details { border: 1px solid var(--line); border-radius: 6px; padding: 4px 8px; }
|
|
31
|
+
details pre { white-space: pre-wrap; word-break: break-word; font-size: 12px; margin: 6px 0 2px; }
|
|
32
|
+
summary { cursor: pointer; font-size: 13px; }
|
|
33
|
+
.error summary { color: #dc2626; }
|
|
34
|
+
.note { color: var(--muted); font-style: italic; font-size: 13px; }
|
|
35
|
+
</style>
|
|
36
|
+
</head>
|
|
37
|
+
<body>
|
|
38
|
+
<header>
|
|
39
|
+
<h1 id="title">gestalt peer</h1>
|
|
40
|
+
<div class="warn">${VIEWER_WARNING}</div>
|
|
41
|
+
<div class="meta">
|
|
42
|
+
<span id="status">연결 중</span>
|
|
43
|
+
<span id="unknown"></span>
|
|
44
|
+
</div>
|
|
45
|
+
</header>
|
|
46
|
+
<main id="log"></main>
|
|
47
|
+
<script nonce="${nonce}">
|
|
48
|
+
(() => {
|
|
49
|
+
const log = document.getElementById('log');
|
|
50
|
+
const statusEl = document.getElementById('status');
|
|
51
|
+
const unknownEl = document.getElementById('unknown');
|
|
52
|
+
const titleEl = document.getElementById('title');
|
|
53
|
+
const params = new URLSearchParams(location.search);
|
|
54
|
+
const token = params.get('t') || '';
|
|
55
|
+
const base = location.pathname.replace(/\\/$/, '');
|
|
56
|
+
const results = new Map();
|
|
57
|
+
|
|
58
|
+
const el = (tag, cls, text) => {
|
|
59
|
+
const n = document.createElement(tag);
|
|
60
|
+
if (cls) n.className = cls;
|
|
61
|
+
if (text !== undefined) n.textContent = text;
|
|
62
|
+
return n;
|
|
63
|
+
};
|
|
64
|
+
const time = (at) => (at ? new Date(at).toLocaleTimeString() : '');
|
|
65
|
+
const atBottom = () => window.innerHeight + window.scrollY >= document.body.scrollHeight - 40;
|
|
66
|
+
|
|
67
|
+
const STATUS = {
|
|
68
|
+
live: '실시간',
|
|
69
|
+
missing: '대화 기록 파일이 안 보여요',
|
|
70
|
+
truncated: '대화 기록이 줄어들어서 멈췄어요',
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
function render(ev) {
|
|
74
|
+
const box = el('div', 'ev ' + ev.kind);
|
|
75
|
+
if (ev.kind === 'prompt' || ev.kind === 'reply') {
|
|
76
|
+
box.append(el('div', 'who', (ev.kind === 'prompt' ? '주인' : '모델') + ' ' + time(ev.at)));
|
|
77
|
+
box.append(el('div', 'text', ev.text));
|
|
78
|
+
} else if (ev.kind === 'tool_call') {
|
|
79
|
+
const d = el('details');
|
|
80
|
+
d.append(el('summary', '', '도구 ' + ev.name + ' ' + time(ev.at)));
|
|
81
|
+
if (ev.input !== undefined) d.append(el('pre', '', ev.input));
|
|
82
|
+
const slot = el('div');
|
|
83
|
+
d.append(slot);
|
|
84
|
+
if (ev.id) results.set(ev.id, slot);
|
|
85
|
+
box.append(d);
|
|
86
|
+
} else if (ev.kind === 'tool_result') {
|
|
87
|
+
const d = el('details', ev.isError ? 'error' : '');
|
|
88
|
+
const label = ev.hidden ? '결과 (주인이 숨김)' : ev.isError ? '결과 (에러)' : '결과';
|
|
89
|
+
d.append(el('summary', '', label + (ev.truncated ? ' · 앞부분만' : '')));
|
|
90
|
+
if (!ev.hidden) d.append(el('pre', '', ev.text || ''));
|
|
91
|
+
const slot = ev.toolUseId ? results.get(ev.toolUseId) : undefined;
|
|
92
|
+
if (slot) { slot.append(d); return; }
|
|
93
|
+
box.append(d);
|
|
94
|
+
} else if (ev.kind === 'title') {
|
|
95
|
+
titleEl.textContent = ev.text;
|
|
96
|
+
document.title = ev.text + ' · gestalt peer';
|
|
97
|
+
return;
|
|
98
|
+
} else if (ev.kind === 'sidechain') {
|
|
99
|
+
box.append(el('div', 'note', '서브에이전트 실행 중'));
|
|
100
|
+
} else if (ev.kind === 'compacted') {
|
|
101
|
+
box.append(el('div', 'note', '이전 대화가 압축됐어요'));
|
|
102
|
+
} else {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
log.append(box);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const eventsUrl = base + '/events?t=' + encodeURIComponent(token);
|
|
109
|
+
const es = new EventSource(eventsUrl);
|
|
110
|
+
es.addEventListener('line', (m) => {
|
|
111
|
+
const stick = atBottom();
|
|
112
|
+
render(JSON.parse(m.data));
|
|
113
|
+
if (stick) window.scrollTo(0, document.body.scrollHeight);
|
|
114
|
+
});
|
|
115
|
+
es.addEventListener('trimmed', (m) => {
|
|
116
|
+
const n = JSON.parse(m.data).dropped;
|
|
117
|
+
log.append(el('div', 'ev note', '메모리 상한에 걸려 앞부분 ' + n + '개를 생략했어요'));
|
|
118
|
+
});
|
|
119
|
+
es.addEventListener('stats', (m) => {
|
|
120
|
+
const n = JSON.parse(m.data).unknownLines;
|
|
121
|
+
unknownEl.textContent = n > 0 ? '모르는 줄 ' + n + '개 건너뜀' : '';
|
|
122
|
+
});
|
|
123
|
+
es.addEventListener('state', (m) => {
|
|
124
|
+
statusEl.textContent = STATUS[JSON.parse(m.data).status] || '';
|
|
125
|
+
});
|
|
126
|
+
es.addEventListener('closed', (m) => {
|
|
127
|
+
statusEl.textContent = '공유가 종료됐어요';
|
|
128
|
+
const missed = JSON.parse(m.data).missed;
|
|
129
|
+
if (missed > 0) {
|
|
130
|
+
log.append(el('div', 'ev note', '공유가 종료돼 뒤쪽 ' + missed + '개는 못 받았어요'));
|
|
131
|
+
}
|
|
132
|
+
es.close();
|
|
133
|
+
});
|
|
134
|
+
// EventSource는 응답 코드를 안 알려 준다. 끊긴 이유가 뷰어 상한(429)인지 한 번 물어본다
|
|
135
|
+
es.onerror = () => {
|
|
136
|
+
if (es.readyState !== EventSource.CLOSED) {
|
|
137
|
+
statusEl.textContent = '다시 연결 중';
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
statusEl.textContent = '연결이 끊겼어요';
|
|
141
|
+
const ctl = new AbortController();
|
|
142
|
+
fetch(eventsUrl, { signal: ctl.signal, cache: 'no-store' })
|
|
143
|
+
.then((r) => {
|
|
144
|
+
ctl.abort();
|
|
145
|
+
if (r.status === 429) {
|
|
146
|
+
statusEl.textContent = '보는 사람 수 상한(${maxViewers}명)에 걸려 못 붙었어요';
|
|
147
|
+
}
|
|
148
|
+
})
|
|
149
|
+
.catch(() => {});
|
|
150
|
+
};
|
|
151
|
+
})();
|
|
152
|
+
</script>
|
|
153
|
+
</body>
|
|
154
|
+
</html>
|
|
155
|
+
`;
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=viewer-html.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"viewer-html.js","sourceRoot":"","sources":["../../../src/peer/viewer-html.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,cAAc,GAAG,0BAA0B,CAAC;AAEzD;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAa,EAAE,UAAkB;IAChE,OAAO;;;;;;;gBAOO,KAAK;;;;;;;;;;;;;;;;;;;;;;;sBAuBC,cAAc;;;;;;;iBAOnB,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+CAmGyB,UAAU;;;;;;;;;CASxD,CAAC;AACF,CAAC"}
|