@tienne/gestalt 0.111.0 → 0.113.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 +3 -3
- package/README.ko.md +1 -1
- package/README.md +1 -1
- package/dist/package.json +3 -1
- package/dist/plugin/role-agents/lens-context/AGENT.md +8 -7
- package/dist/plugin/role-agents/lens-reader/AGENT.md +48 -2
- package/dist/plugin/skills/lens/SKILL.md +22 -15
- package/dist/src/architecture/doc-fresh.d.ts.map +1 -1
- package/dist/src/architecture/doc-fresh.js +3 -1
- package/dist/src/architecture/doc-fresh.js.map +1 -1
- package/dist/src/cli/commands/lens.d.ts +8 -1
- package/dist/src/cli/commands/lens.d.ts.map +1 -1
- package/dist/src/cli/commands/lens.js +29 -2
- package/dist/src/cli/commands/lens.js.map +1 -1
- package/dist/src/cli/commands/peer.d.ts +20 -0
- package/dist/src/cli/commands/peer.d.ts.map +1 -1
- package/dist/src/cli/commands/peer.js +198 -12
- package/dist/src/cli/commands/peer.js.map +1 -1
- package/dist/src/cli/index.d.ts.map +1 -1
- package/dist/src/cli/index.js +44 -4
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/digest/lens-schema.d.ts +150 -3
- package/dist/src/digest/lens-schema.d.ts.map +1 -1
- package/dist/src/digest/lens-schema.js +14 -1
- package/dist/src/digest/lens-schema.js.map +1 -1
- package/dist/src/digest/lens-widget-schema.d.ts +2 -2
- package/dist/src/digest/lint-lens.d.ts +2 -1
- package/dist/src/digest/lint-lens.d.ts.map +1 -1
- package/dist/src/digest/lint-lens.js +68 -7
- package/dist/src/digest/lint-lens.js.map +1 -1
- package/dist/src/digest/ocr.d.ts +1 -1
- package/dist/src/digest/ocr.d.ts.map +1 -1
- package/dist/src/digest/ocr.js +10 -4
- package/dist/src/digest/ocr.js.map +1 -1
- package/dist/src/digest/schema.d.ts +62 -62
- package/dist/src/lens/attach.d.ts +741 -0
- package/dist/src/lens/attach.d.ts.map +1 -1
- package/dist/src/lens/attach.js +41 -11
- package/dist/src/lens/attach.js.map +1 -1
- package/dist/src/lens/context-input.d.ts +17 -0
- package/dist/src/lens/context-input.d.ts.map +1 -0
- package/dist/src/lens/context-input.js +31 -0
- package/dist/src/lens/context-input.js.map +1 -0
- package/dist/src/lens/ingest.d.ts +19 -1
- package/dist/src/lens/ingest.d.ts.map +1 -1
- package/dist/src/lens/ingest.js +92 -14
- package/dist/src/lens/ingest.js.map +1 -1
- package/dist/src/lens/pdf-extract-py.d.ts +2 -0
- package/dist/src/lens/pdf-extract-py.d.ts.map +1 -1
- package/dist/src/lens/pdf-extract-py.js +37 -2
- package/dist/src/lens/pdf-extract-py.js.map +1 -1
- package/dist/src/mcp/schemas.d.ts +29 -0
- package/dist/src/mcp/schemas.d.ts.map +1 -1
- package/dist/src/mcp/schemas.js +29 -0
- package/dist/src/mcp/schemas.js.map +1 -1
- package/dist/src/mcp/server.d.ts.map +1 -1
- package/dist/src/mcp/server.js +6 -1
- package/dist/src/mcp/server.js.map +1 -1
- package/dist/src/mcp/tools/architecture-passthrough.d.ts.map +1 -1
- package/dist/src/mcp/tools/architecture-passthrough.js +1 -1
- package/dist/src/mcp/tools/architecture-passthrough.js.map +1 -1
- package/dist/src/mcp/tools/peer.d.ts +24 -0
- package/dist/src/mcp/tools/peer.d.ts.map +1 -0
- package/dist/src/mcp/tools/peer.js +103 -0
- package/dist/src/mcp/tools/peer.js.map +1 -0
- package/dist/src/peer/codex.d.ts +57 -0
- package/dist/src/peer/codex.d.ts.map +1 -0
- package/dist/src/peer/codex.js +303 -0
- package/dist/src/peer/codex.js.map +1 -0
- package/dist/src/peer/daemon.d.ts +76 -1
- package/dist/src/peer/daemon.d.ts.map +1 -1
- package/dist/src/peer/daemon.js +511 -19
- package/dist/src/peer/daemon.js.map +1 -1
- package/dist/src/peer/errors.d.ts +3 -0
- package/dist/src/peer/errors.d.ts.map +1 -1
- package/dist/src/peer/errors.js +3 -0
- package/dist/src/peer/errors.js.map +1 -1
- package/dist/src/peer/excerpt.d.ts +47 -0
- package/dist/src/peer/excerpt.d.ts.map +1 -0
- package/dist/src/peer/excerpt.js +160 -0
- package/dist/src/peer/excerpt.js.map +1 -0
- package/dist/src/peer/feed.d.ts +35 -2
- package/dist/src/peer/feed.d.ts.map +1 -1
- package/dist/src/peer/feed.js +22 -0
- package/dist/src/peer/feed.js.map +1 -1
- package/dist/src/peer/inbox.d.ts +42 -0
- package/dist/src/peer/inbox.d.ts.map +1 -0
- package/dist/src/peer/inbox.js +96 -0
- package/dist/src/peer/inbox.js.map +1 -0
- package/dist/src/peer/locate.d.ts +5 -0
- package/dist/src/peer/locate.d.ts.map +1 -1
- package/dist/src/peer/locate.js +19 -2
- package/dist/src/peer/locate.js.map +1 -1
- package/dist/src/peer/message.d.ts +113 -0
- package/dist/src/peer/message.d.ts.map +1 -0
- package/dist/src/peer/message.js +183 -0
- package/dist/src/peer/message.js.map +1 -0
- package/dist/src/peer/mirror.d.ts +50 -1
- package/dist/src/peer/mirror.d.ts.map +1 -1
- package/dist/src/peer/mirror.js +138 -0
- package/dist/src/peer/mirror.js.map +1 -1
- package/dist/src/peer/network.d.ts +229 -1
- package/dist/src/peer/network.d.ts.map +1 -1
- package/dist/src/peer/network.js +867 -44
- package/dist/src/peer/network.js.map +1 -1
- package/dist/src/peer/paths.d.ts +6 -0
- package/dist/src/peer/paths.d.ts.map +1 -1
- package/dist/src/peer/paths.js +8 -0
- package/dist/src/peer/paths.js.map +1 -1
- package/dist/src/peer/peek.d.ts +79 -0
- package/dist/src/peer/peek.d.ts.map +1 -0
- package/dist/src/peer/peek.js +465 -0
- package/dist/src/peer/peek.js.map +1 -0
- package/dist/src/peer/peeks.d.ts +115 -0
- package/dist/src/peer/peeks.d.ts.map +1 -0
- package/dist/src/peer/peeks.js +262 -0
- package/dist/src/peer/peeks.js.map +1 -0
- package/dist/src/peer/protocol.d.ts +128 -4
- package/dist/src/peer/protocol.d.ts.map +1 -1
- package/dist/src/peer/protocol.js.map +1 -1
- package/dist/src/peer/questions.d.ts +168 -0
- package/dist/src/peer/questions.d.ts.map +1 -0
- package/dist/src/peer/questions.js +389 -0
- package/dist/src/peer/questions.js.map +1 -0
- package/dist/src/peer/relay.d.ts +14 -0
- package/dist/src/peer/relay.d.ts.map +1 -1
- package/dist/src/peer/relay.js +102 -7
- package/dist/src/peer/relay.js.map +1 -1
- package/dist/src/peer/roster.d.ts +2 -0
- package/dist/src/peer/roster.d.ts.map +1 -1
- package/dist/src/peer/roster.js +5 -0
- package/dist/src/peer/roster.js.map +1 -1
- package/dist/src/peer/share.d.ts +48 -1
- package/dist/src/peer/share.d.ts.map +1 -1
- package/dist/src/peer/share.js +167 -2
- package/dist/src/peer/share.js.map +1 -1
- package/dist/src/peer/state.d.ts +12 -1
- package/dist/src/peer/state.d.ts.map +1 -1
- package/dist/src/peer/state.js +15 -0
- package/dist/src/peer/state.js.map +1 -1
- package/dist/src/peer/transform.d.ts +32 -0
- package/dist/src/peer/transform.d.ts.map +1 -1
- package/dist/src/peer/transform.js +52 -33
- package/dist/src/peer/transform.js.map +1 -1
- package/dist/src/peer/transport.d.ts +7 -3
- package/dist/src/peer/transport.d.ts.map +1 -1
- package/dist/src/peer/transport.js +12 -4
- package/dist/src/peer/transport.js.map +1 -1
- package/dist/src/peer/viewer-html.d.ts +13 -1
- package/dist/src/peer/viewer-html.d.ts.map +1 -1
- package/dist/src/peer/viewer-html.js +328 -4
- package/dist/src/peer/viewer-html.js.map +1 -1
- package/dist/src/peer/viewer.d.ts +49 -1
- package/dist/src/peer/viewer.d.ts.map +1 -1
- package/dist/src/peer/viewer.js +133 -7
- package/dist/src/peer/viewer.js.map +1 -1
- package/dist/src/peer/wire.d.ts +9 -2
- package/dist/src/peer/wire.d.ts.map +1 -1
- package/dist/src/peer/wire.js.map +1 -1
- package/package.json +3 -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 +8 -7
- package/plugin/role-agents/lens-reader/AGENT.md +48 -2
- package/plugin/skills/lens/SKILL.md +22 -15
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import { errMessage, PeerNetworkError } from './errors.js';
|
|
2
|
+
import { MESSAGE_RECEIVE_LIMIT, plainLabel, RateLimiter } from './message.js';
|
|
3
|
+
import { isPeekCursor, isPeekId, newPeekId, normalizePeek, peekJson } from './peek.js';
|
|
4
|
+
import { isShareId } from './roster.js';
|
|
5
|
+
import { canonical, hmac, safeEqual } from './seal.js';
|
|
6
|
+
import { RelaySendError } from './transport.js';
|
|
7
|
+
/**
|
|
8
|
+
* ges_peer peek의 봉인 요청과 답. 보는 쪽(요청 보내기, 답 받기)과 주인 쪽(요청 검사, 요약 주기, 훅
|
|
9
|
+
* 알림)이 다 여기 있다. 요약을 만드는 건 peek.ts다. 통로와 명단, 승인 기록은 PeerNetwork가 들고
|
|
10
|
+
* 있고 이 쪽은 PeekHost로만 닿는다.
|
|
11
|
+
*/
|
|
12
|
+
/** 요약을 가져갔다고 주인 세션에 알리는 시간. 이 동안 보는 중 표시 훅이 한 줄을 붙인다 */
|
|
13
|
+
export const PEEK_NOTICE_MS = 10 * 60 * 1000;
|
|
14
|
+
/** 보는 쪽이 요약 답을 기다리는 시한. 이전 버전 주인 데몬은 peek을 몰라서 답하지 않는다 */
|
|
15
|
+
export const PEEK_TIMEOUT_MS = 10_000;
|
|
16
|
+
/** 보는 쪽에서 답을 기다리는 요약 요청 수 */
|
|
17
|
+
const MAX_PENDING_PEEKS = 16;
|
|
18
|
+
/** 주인 쪽이 기억하는 요약 요청 id 수. PeerNetwork의 메시지 기억(seenMessages)과는 따로 센다 */
|
|
19
|
+
const MAX_SEEN_PEEKS = 4096;
|
|
20
|
+
/**
|
|
21
|
+
* 주인 데몬이 보낼 수 있는 거절 이유. 이 밖의 글자는 unknown으로 바꾼다. 거절 문구는 MCP 오류로 보는
|
|
22
|
+
* 쪽 모델에 들어가므로 주인 데몬이 지어낸 글자를 싣지 않는다
|
|
23
|
+
*/
|
|
24
|
+
const PEEK_REASONS = new Set([
|
|
25
|
+
'share_closed',
|
|
26
|
+
'bad_frame',
|
|
27
|
+
'bad_proof',
|
|
28
|
+
'kicked',
|
|
29
|
+
'denied',
|
|
30
|
+
'not_approved',
|
|
31
|
+
'peek_off',
|
|
32
|
+
'rate_limited',
|
|
33
|
+
]);
|
|
34
|
+
export class PeekDesk {
|
|
35
|
+
host;
|
|
36
|
+
/** 주인 쪽. 같은 기기가 같은 공유(`공유|기기`)에서 요약을 가져가는 수. 10분에 36번 */
|
|
37
|
+
limiter = new RateLimiter(MESSAGE_RECEIVE_LIMIT);
|
|
38
|
+
/** 주인 쪽. 증명이 맞은 요청의 `기기|id`. 릴레이가 같은 봉인을 다시 보내면 버린다 */
|
|
39
|
+
seen = new Set();
|
|
40
|
+
/** 주인 쪽. 공유마다 최근 요약을 가져간 사람(명단 이름)과 시각. 알리는 시간이 지나면 지운다 */
|
|
41
|
+
peeked = new Map();
|
|
42
|
+
/** 보는 쪽. 답을 기다리는 요약 요청. 키는 요청 id */
|
|
43
|
+
pending = new Map();
|
|
44
|
+
noticeMs;
|
|
45
|
+
timeoutMs;
|
|
46
|
+
constructor(host, options = {}) {
|
|
47
|
+
this.host = host;
|
|
48
|
+
this.noticeMs = options.noticeMs ?? PEEK_NOTICE_MS;
|
|
49
|
+
this.timeoutMs = options.timeoutMs ?? PEEK_TIMEOUT_MS;
|
|
50
|
+
}
|
|
51
|
+
stop() {
|
|
52
|
+
for (const map of this.peeked.values())
|
|
53
|
+
for (const p of map.values())
|
|
54
|
+
clearTimeout(p.timer);
|
|
55
|
+
this.peeked.clear();
|
|
56
|
+
for (const p of this.pending.values()) {
|
|
57
|
+
clearTimeout(p.timer);
|
|
58
|
+
p.reject(new PeerNetworkError('데몬이 멈췄어요'));
|
|
59
|
+
}
|
|
60
|
+
this.pending.clear();
|
|
61
|
+
}
|
|
62
|
+
/** 요약 봉인을 받는다. PeerNetwork.onReceive가 넘긴다 */
|
|
63
|
+
receive(from, msg) {
|
|
64
|
+
if (msg.t === 'peek')
|
|
65
|
+
this.onRequest(from, msg);
|
|
66
|
+
else
|
|
67
|
+
this.onReply(from, msg);
|
|
68
|
+
}
|
|
69
|
+
/** 주인 쪽: 그 공유에서 최근 요약을 가져간 사람 */
|
|
70
|
+
notices(share) {
|
|
71
|
+
return [...(this.peeked.get(share) ?? [])].map(([person, p]) => ({ person, at: p.at }));
|
|
72
|
+
}
|
|
73
|
+
/** 주인 쪽: 공유가 닫혔다. 그 공유의 알림을 버린다 */
|
|
74
|
+
forget(share) {
|
|
75
|
+
for (const p of this.peeked.get(share)?.values() ?? [])
|
|
76
|
+
clearTimeout(p.timer);
|
|
77
|
+
this.peeked.delete(share);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* 보는 쪽: 보고 있는 공유의 요약을 주인 데몬에 청한다. target은 주인 쪽 공유 id이고 보기 id도
|
|
81
|
+
* 받는다. 증명은 메시지처럼 링크의 공유 키로 만든다. 받아 줄지는 주인 데몬이 명단과 증명, 승인과
|
|
82
|
+
* kick 기록으로 정한다. 받은 요약은 주인 데몬이 보낸 값이라 꼴과 크기를 다시 본다.
|
|
83
|
+
*/
|
|
84
|
+
async peek(target, since) {
|
|
85
|
+
if (!isShareId(target))
|
|
86
|
+
throw new PeerNetworkError('공유 id 꼴이 아니에요');
|
|
87
|
+
if (since !== undefined && !isPeekCursor(since)) {
|
|
88
|
+
throw new PeerNetworkError('since는 앞 peek이 돌려준 cursor예요');
|
|
89
|
+
}
|
|
90
|
+
const list = [...this.host.watches()];
|
|
91
|
+
const w = list.find((x) => x.share === target) ?? list.find((x) => x.id === target);
|
|
92
|
+
if (!w) {
|
|
93
|
+
const open = list.map((x) => `${x.share} (${plainLabel(x.feed.ownerPerson, 32) ?? '?'})`);
|
|
94
|
+
throw new PeerNetworkError(open.length === 0
|
|
95
|
+
? '보고 있는 공유가 없어요. 사람이 `gestalt peer watch <링크>`로 먼저 열어야 해요'
|
|
96
|
+
: `보고 있는 공유가 아니에요: ${target}. 지금 보는 공유는 ${open.join(', ')}예요`);
|
|
97
|
+
}
|
|
98
|
+
if (this.pending.size >= MAX_PENDING_PEEKS) {
|
|
99
|
+
throw new PeerNetworkError('답을 기다리는 요약 요청이 많아요. 조금 뒤에 다시 불러 주세요');
|
|
100
|
+
}
|
|
101
|
+
const id = newPeekId();
|
|
102
|
+
const send = this.host.prepareDirect(w.owner, {
|
|
103
|
+
t: 'peek',
|
|
104
|
+
share: w.share,
|
|
105
|
+
id,
|
|
106
|
+
...(since !== undefined ? { since } : {}),
|
|
107
|
+
proof: hmac(w.shareKey, peekProofText(w.share, this.host.key.id, id, since)),
|
|
108
|
+
});
|
|
109
|
+
const reply = new Promise((resolve, reject) => {
|
|
110
|
+
const timer = setTimeout(() => {
|
|
111
|
+
this.pending.delete(id);
|
|
112
|
+
reject(new PeerNetworkError('주인 데몬이 답하지 않았어요. 요약을 모르는 이전 버전일 수 있어요'));
|
|
113
|
+
}, this.timeoutMs);
|
|
114
|
+
timer.unref();
|
|
115
|
+
this.pending.set(id, {
|
|
116
|
+
owner: w.owner,
|
|
117
|
+
share: w.share,
|
|
118
|
+
person: w.feed.ownerPerson,
|
|
119
|
+
resolve,
|
|
120
|
+
reject,
|
|
121
|
+
timer,
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
// 릴레이 ack를 기다리는 사이에 답이나 시한이 먼저 올 수 있다. 그때 reply를 아무도 안 잡고 있으면
|
|
125
|
+
// 처리되지 않은 reject로 데몬이 죽는다. 부르는 쪽은 아래 return으로 같은 reject를 그대로 받는다
|
|
126
|
+
reply.catch(() => { });
|
|
127
|
+
try {
|
|
128
|
+
await send();
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
const p = this.pending.get(id);
|
|
132
|
+
if (p) {
|
|
133
|
+
clearTimeout(p.timer);
|
|
134
|
+
this.pending.delete(id);
|
|
135
|
+
}
|
|
136
|
+
const reason = err instanceof RelaySendError ? err.reason : errMessage(err);
|
|
137
|
+
throw new PeerNetworkError(`주인 데몬에 요약을 요청하지 못했어요 (${plainLabel(reason, 64)})`);
|
|
138
|
+
}
|
|
139
|
+
return reply;
|
|
140
|
+
}
|
|
141
|
+
/** 보는 쪽: 주인 데몬의 요약 답. id와 보낸 기기, 공유가 내가 낸 요청과 맞는 답만 꺼낸다 */
|
|
142
|
+
onReply(from, msg) {
|
|
143
|
+
if (!isPeekId(msg.id))
|
|
144
|
+
return;
|
|
145
|
+
const p = this.pending.get(msg.id);
|
|
146
|
+
if (!p || p.owner !== from || p.share !== msg.share)
|
|
147
|
+
return;
|
|
148
|
+
clearTimeout(p.timer);
|
|
149
|
+
this.pending.delete(msg.id);
|
|
150
|
+
if (msg.peek === undefined) {
|
|
151
|
+
const reason = typeof msg.reason === 'string' && PEEK_REASONS.has(msg.reason) ? msg.reason : 'unknown';
|
|
152
|
+
return p.reject(new PeerNetworkError(peekRefusalText(reason)));
|
|
153
|
+
}
|
|
154
|
+
const peek = normalizePeek(msg.peek);
|
|
155
|
+
if (!peek || peek.share !== p.share) {
|
|
156
|
+
return p.reject(new PeerNetworkError('주인 데몬이 보낸 요약 꼴이 맞지 않아요'));
|
|
157
|
+
}
|
|
158
|
+
this.host.state.audit('peek_receive', null, JSON.stringify({ share: p.share, owner: plainLabel(p.person, 32) ?? '?' }));
|
|
159
|
+
p.resolve({ peek, owner: p.person });
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* 주인 쪽: 요약 요청을 검사하고 답한다. 메시지처럼 구독이 아니라 링크 증명과 승인, kick 기록으로
|
|
163
|
+
* 본다. 그래서 구독이 끊긴 사람도 받아 준 기기면 가져가고 승인 전이나 kick된 기기는 막힌다.
|
|
164
|
+
* 순서는 꼴 → 공유 → 증명 → 승인과 kick → `--agent-peek` → 횟수다. 가져가면 감사 로그에 남기고
|
|
165
|
+
* 보는 중 표시 훅으로 주인 세션에 한동안 알린다.
|
|
166
|
+
*/
|
|
167
|
+
onRequest(from, msg) {
|
|
168
|
+
// 꼴이 틀린 id는 감사 로그와 답으로 흘러가지 않게 답 없이 버린다. network.test.ts의 "꼴이 틀린 공유
|
|
169
|
+
// id나 요청 id의 요약 요청은 답도 감사 행도 없이 버린다"가 본다
|
|
170
|
+
if (!isShareId(msg.share) || !isPeekId(msg.id))
|
|
171
|
+
return;
|
|
172
|
+
const dedupe = `${from}|${msg.id}`;
|
|
173
|
+
if (this.seen.has(dedupe))
|
|
174
|
+
return;
|
|
175
|
+
const person = this.host.personOf(from);
|
|
176
|
+
const reject = (reason) => {
|
|
177
|
+
if (!this.host.takeReject(from))
|
|
178
|
+
return;
|
|
179
|
+
this.host.sendBox(from, { t: 'peek_reply', share: msg.share, id: msg.id, reason });
|
|
180
|
+
this.host.state.audit('peek_reject', msg.share, JSON.stringify({ id: msg.id, person, reason }));
|
|
181
|
+
};
|
|
182
|
+
const owned = this.host.lookupShare(msg.share);
|
|
183
|
+
if (!owned || owned.stream.isClosed)
|
|
184
|
+
return reject('share_closed');
|
|
185
|
+
if (typeof msg.proof !== 'string' || (msg.since !== undefined && !isPeekCursor(msg.since))) {
|
|
186
|
+
return reject('bad_frame');
|
|
187
|
+
}
|
|
188
|
+
const expected = hmac(Buffer.from(owned.shareKey, 'base64url'), peekProofText(msg.share, from, msg.id, msg.since));
|
|
189
|
+
if (!safeEqual(msg.proof, expected))
|
|
190
|
+
return reject('bad_proof');
|
|
191
|
+
// 기억은 증명이 맞은 뒤에 한다. 앞에서 기억하면 증명 없는 가짜 id로 칸을 밀어낼 수 있다. 거절한
|
|
192
|
+
// 요청도 기억해서 다시 와도 답과 감사 행을 또 쓰지 않는다. 요약 요청 id는 PeekDesk.seen에만
|
|
193
|
+
// 기억하고 PeerNetwork의 seenMessages와 같이 쓰지 않는다
|
|
194
|
+
this.seen.add(dedupe);
|
|
195
|
+
if (this.seen.size > MAX_SEEN_PEEKS) {
|
|
196
|
+
const oldest = this.seen.values().next().value;
|
|
197
|
+
if (oldest !== undefined)
|
|
198
|
+
this.seen.delete(oldest);
|
|
199
|
+
}
|
|
200
|
+
const refusal = this.host.refusal(msg.share, from);
|
|
201
|
+
if (refusal)
|
|
202
|
+
return reject(refusal);
|
|
203
|
+
if (!owned.peek)
|
|
204
|
+
return reject('peek_off');
|
|
205
|
+
if (!this.limiter.take(`${msg.share}|${from}`))
|
|
206
|
+
return reject('rate_limited');
|
|
207
|
+
const peek = owned.peek(msg.since);
|
|
208
|
+
this.host.sendBox(from, { t: 'peek_reply', share: msg.share, id: msg.id, peek });
|
|
209
|
+
this.host.state.audit('peek_serve', msg.share, JSON.stringify({
|
|
210
|
+
id: msg.id,
|
|
211
|
+
person,
|
|
212
|
+
since: msg.since ?? null,
|
|
213
|
+
bytes: Buffer.byteLength(peekJson(peek)),
|
|
214
|
+
}));
|
|
215
|
+
this.note(msg.share, person);
|
|
216
|
+
}
|
|
217
|
+
/** 주인 쪽: 요약을 가져간 사람을 알리는 시간 동안 기억한다. 다시 가져가면 시간을 새로 잰다 */
|
|
218
|
+
note(share, person) {
|
|
219
|
+
let map = this.peeked.get(share);
|
|
220
|
+
if (!map) {
|
|
221
|
+
map = new Map();
|
|
222
|
+
this.peeked.set(share, map);
|
|
223
|
+
}
|
|
224
|
+
const prev = map.get(person);
|
|
225
|
+
if (prev)
|
|
226
|
+
clearTimeout(prev.timer);
|
|
227
|
+
const timer = setTimeout(() => {
|
|
228
|
+
const m = this.peeked.get(share);
|
|
229
|
+
if (m?.get(person)?.timer !== timer)
|
|
230
|
+
return;
|
|
231
|
+
m.delete(person);
|
|
232
|
+
if (m.size === 0)
|
|
233
|
+
this.peeked.delete(share);
|
|
234
|
+
this.host.changed();
|
|
235
|
+
}, this.noticeMs);
|
|
236
|
+
timer.unref();
|
|
237
|
+
map.set(person, { at: Date.now(), timer });
|
|
238
|
+
this.host.changed();
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
/** 요약 거절 이유를 사람이 읽는 문장으로. 이유 글자는 끝에 괄호로 남겨 스크립트가 찾게 한다 */
|
|
242
|
+
export function peekRefusalText(reason) {
|
|
243
|
+
switch (reason) {
|
|
244
|
+
case 'peek_off':
|
|
245
|
+
return '주인이 에이전트 요약을 허락하지 않았어요. 주인이 공유를 --agent-peek으로 열어야 해요 (peek_off)';
|
|
246
|
+
case 'not_approved':
|
|
247
|
+
return '주인이 아직 받아 주지 않았어요 (not_approved)';
|
|
248
|
+
case 'kicked':
|
|
249
|
+
return '주인이 이 공유에서 끊었어요 (kicked)';
|
|
250
|
+
case 'denied':
|
|
251
|
+
return '주인이 거절했어요 (denied)';
|
|
252
|
+
case 'rate_limited':
|
|
253
|
+
return '요약을 너무 자주 가져갔어요. 10분에 36번까지예요 (rate_limited)';
|
|
254
|
+
default:
|
|
255
|
+
return `주인 데몬이 요약을 거절했어요 (${reason})`;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
/** 링크를 가진 쪽만 만드는 요약 요청 증명. 요청 id와 since까지 넣어 릴레이가 바꾸지 못하게 한다 */
|
|
259
|
+
export function peekProofText(share, from, id, since) {
|
|
260
|
+
return canonical({ p: 'gestalt-peer-peek-v1', share, from, id, since: since ?? '' });
|
|
261
|
+
}
|
|
262
|
+
//# sourceMappingURL=peeks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"peeks.js","sourceRoot":"","sources":["../../../src/peer/peeks.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { ToolsLevel } from './redact.js';
|
|
2
2
|
import type { ShareStatus } from './feed.js';
|
|
3
3
|
import type { MemberInfo, TeamStatus } from './network.js';
|
|
4
|
-
|
|
4
|
+
import type { AskResult } from './questions.js';
|
|
5
|
+
import type { TranscriptFormat } from './share.js';
|
|
6
|
+
export type { AskResult, MemberInfo, TeamStatus, TranscriptFormat };
|
|
5
7
|
/** IPC 한 줄 요청. 줄 단위 JSON이다 */
|
|
6
8
|
export type PeerRequest = {
|
|
7
9
|
op: 'ping';
|
|
@@ -15,6 +17,12 @@ export type PeerRequest = {
|
|
|
15
17
|
sessionId?: string;
|
|
16
18
|
tools?: ToolsLevel;
|
|
17
19
|
expiresMinutes?: number;
|
|
20
|
+
/** false면 이 공유는 팀원 메시지를 안 받는다. 기본은 받는다 */
|
|
21
|
+
messages?: boolean;
|
|
22
|
+
/** 대화 기록 형식. 기본 claude. codex면 메시지를 안 받고 sessionId를 받지 않는다 */
|
|
23
|
+
format?: TranscriptFormat;
|
|
24
|
+
/** true면 보는 쪽 에이전트가 ges_peer peek으로 요약을 가져갈 수 있다. 기본은 꺼짐 */
|
|
25
|
+
agentPeek?: boolean;
|
|
18
26
|
} | {
|
|
19
27
|
op: 'unshare';
|
|
20
28
|
id: string;
|
|
@@ -34,14 +42,71 @@ export type PeerRequest = {
|
|
|
34
42
|
person: string;
|
|
35
43
|
} | {
|
|
36
44
|
op: 'members';
|
|
37
|
-
}
|
|
45
|
+
}
|
|
46
|
+
/** configDir은 명령을 친 쪽의 Claude Code 설정 디렉토리. 발췌를 넣을 내 세션 목록을 거기서도 찾는다 */
|
|
47
|
+
| {
|
|
38
48
|
op: 'watch';
|
|
39
49
|
link: string;
|
|
50
|
+
configDir?: string;
|
|
40
51
|
} | {
|
|
41
52
|
op: 'watches';
|
|
42
53
|
} | {
|
|
43
54
|
op: 'unwatch';
|
|
44
55
|
id: string;
|
|
56
|
+
}
|
|
57
|
+
/** 보고 있는 원격 공유의 주인 세션에 메시지를 넣는다 */
|
|
58
|
+
| {
|
|
59
|
+
op: 'send';
|
|
60
|
+
watch: string;
|
|
61
|
+
body: string;
|
|
62
|
+
}
|
|
63
|
+
/** watch가 있으면 그 보기에서 내가 보낸 메시지, 없으면 내 공유가 받은 메시지 기록 */
|
|
64
|
+
| {
|
|
65
|
+
op: 'messages';
|
|
66
|
+
watch?: string;
|
|
67
|
+
}
|
|
68
|
+
/** 그 사람을 내 공유에서 끊는다. share가 없으면 열린 공유 전부다 */
|
|
69
|
+
| {
|
|
70
|
+
op: 'kick';
|
|
71
|
+
person: string;
|
|
72
|
+
share?: string;
|
|
73
|
+
}
|
|
74
|
+
/** 처음 붙으려고 기다리는 사람을 받아 준다 */
|
|
75
|
+
| {
|
|
76
|
+
op: 'approve';
|
|
77
|
+
person: string;
|
|
78
|
+
share?: string;
|
|
79
|
+
}
|
|
80
|
+
/** 처음 붙으려고 기다리는 사람을 거절한다. 그 공유가 열려 있는 동안 다시 못 붙는다 */
|
|
81
|
+
| {
|
|
82
|
+
op: 'deny';
|
|
83
|
+
person: string;
|
|
84
|
+
share?: string;
|
|
85
|
+
}
|
|
86
|
+
/** firstWatch가 있으면 바꾸고 지금 설정을 돌려준다 */
|
|
87
|
+
| {
|
|
88
|
+
op: 'config';
|
|
89
|
+
firstWatch?: FirstWatchApproval;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* 주인 세션 모델의 질문을 그 세션 공유를 보는 팀원에게 보낸다(ges_peer ask_user). to를 주면 그 사람만.
|
|
93
|
+
* 답은 나중에 그 세션 인박스로 들어온다
|
|
94
|
+
*/
|
|
95
|
+
| {
|
|
96
|
+
op: 'ask';
|
|
97
|
+
sessionId: string;
|
|
98
|
+
question: string;
|
|
99
|
+
to?: string;
|
|
100
|
+
timeoutSecs?: number;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* 보고 있는 원격 공유의 요약을 주인 데몬에 청한다(ges_peer peek). share는 주인 쪽 공유 id이고 보기
|
|
104
|
+
* id도 받는다. since는 앞 요약의 cursor다
|
|
105
|
+
*/
|
|
106
|
+
| {
|
|
107
|
+
op: 'peek';
|
|
108
|
+
share: string;
|
|
109
|
+
since?: string;
|
|
45
110
|
};
|
|
46
111
|
export type PeerResponse<T = unknown> = {
|
|
47
112
|
ok: true;
|
|
@@ -55,6 +120,12 @@ export interface ShareInfo {
|
|
|
55
120
|
sessionId: string | null;
|
|
56
121
|
transcriptPath: string;
|
|
57
122
|
tools: ToolsLevel;
|
|
123
|
+
/** 대화 기록 형식 */
|
|
124
|
+
format: TranscriptFormat;
|
|
125
|
+
/** 팀원 메시지를 받는지 */
|
|
126
|
+
messages: boolean;
|
|
127
|
+
/** 보는 쪽 에이전트가 요약(peek)을 가져갈 수 있는지. `--agent-peek`으로 연 공유만 true */
|
|
128
|
+
agentPeek: boolean;
|
|
58
129
|
createdAt: number;
|
|
59
130
|
expiresAt: number;
|
|
60
131
|
status: ShareStatus;
|
|
@@ -71,20 +142,73 @@ export interface ShareInfo {
|
|
|
71
142
|
url: string;
|
|
72
143
|
/** 팀에 들었으면 팀원에게 건넬 링크. 공유 키가 `#` 뒤에 붙는다 */
|
|
73
144
|
link?: string;
|
|
145
|
+
/** 원격으로 보고 있는 사람 이름. 명단에서 온 값이다 */
|
|
146
|
+
watchers: string[];
|
|
147
|
+
/** 주인 승인을 기다리는 사람 */
|
|
148
|
+
pending: PendingWatcher[];
|
|
149
|
+
/** 이 공유에서 끊거나 거절해 다시 못 붙는 사람 */
|
|
150
|
+
blocked: {
|
|
151
|
+
person: string;
|
|
152
|
+
reason: BlockReason;
|
|
153
|
+
}[];
|
|
154
|
+
/** 최근 요약을 가져간 사람. 주인 세션에 알리는 시간(10분)이 지나면 빠진다 */
|
|
155
|
+
peeks: PeekNotice[];
|
|
156
|
+
}
|
|
157
|
+
/** 요약을 가져간 사람 한 명. 이름은 명단에서 온 값을 한 줄 라벨로 정리한 것이다 */
|
|
158
|
+
export interface PeekNotice {
|
|
159
|
+
person: string;
|
|
160
|
+
/** 마지막으로 가져간 시각 */
|
|
161
|
+
at: number;
|
|
162
|
+
}
|
|
163
|
+
/** ges_peer peek의 답. text는 보는 쪽 에이전트에 그대로 넘기는 틀로 감싼 글자다 */
|
|
164
|
+
export interface PeekResult {
|
|
165
|
+
share: string;
|
|
166
|
+
owner: string;
|
|
167
|
+
cursor: string;
|
|
168
|
+
text: string;
|
|
169
|
+
}
|
|
170
|
+
export interface PendingWatcher {
|
|
171
|
+
person: string;
|
|
172
|
+
/** 처음 청한 시각 */
|
|
173
|
+
at: number;
|
|
174
|
+
/** 이때까지 안 받아 주면 approval_timeout으로 끝난다 */
|
|
175
|
+
expiresAt: number;
|
|
176
|
+
/** 훅이 긴 안내를 한동안 붙였으면 true. 그 뒤로는 짧은 한 줄만 붙인다 */
|
|
177
|
+
brief?: boolean;
|
|
178
|
+
}
|
|
179
|
+
export type BlockReason = 'kicked' | 'denied';
|
|
180
|
+
/** kick, approve, deny의 답 */
|
|
181
|
+
export interface ControlResult {
|
|
182
|
+
person: string;
|
|
183
|
+
/** 손댄 공유 id */
|
|
184
|
+
shares: string[];
|
|
185
|
+
/** kick이면 끊은 구독 수, approve와 deny면 처리한 요청 수 */
|
|
186
|
+
count: number;
|
|
187
|
+
}
|
|
188
|
+
export interface PeerConfig {
|
|
189
|
+
firstWatch: FirstWatchApproval;
|
|
190
|
+
/** 바꿀 때만 있다. ask로 조여 승인을 거두고 끊은 구독 수 */
|
|
191
|
+
revoked?: number;
|
|
74
192
|
}
|
|
75
193
|
export interface WatchResult {
|
|
76
194
|
id: string;
|
|
77
195
|
share: string;
|
|
78
196
|
owner: string;
|
|
79
197
|
url: string;
|
|
198
|
+
/** 주인 승인을 기다리는 중이면 true. 받아 주면 뷰어에 대화가 보이기 시작한다 */
|
|
199
|
+
waiting?: boolean;
|
|
80
200
|
}
|
|
81
201
|
export interface WatchListItem {
|
|
82
202
|
id: string;
|
|
83
203
|
share: string;
|
|
84
204
|
owner: string;
|
|
205
|
+
/** live, offline, waiting(주인 승인 기다리는 중) 같은 상태 */
|
|
85
206
|
status: string;
|
|
86
207
|
events: number;
|
|
87
|
-
|
|
208
|
+
/** 끝난 보기면 없다 */
|
|
209
|
+
url?: string;
|
|
210
|
+
/** 끝난 보기면 그 이유(kicked, denied, approval_timeout, unshare 등) */
|
|
211
|
+
closed?: string;
|
|
88
212
|
}
|
|
89
213
|
export interface DaemonStatus {
|
|
90
214
|
pid: number;
|
|
@@ -101,7 +225,7 @@ export interface DaemonStatus {
|
|
|
101
225
|
export declare const MAX_REQUEST_BYTES: number;
|
|
102
226
|
/**
|
|
103
227
|
* 처음 붙는 팀원을 받는 방식. ask는 주인이 받아 주고 team은 명단에 있으면 바로 받는다.
|
|
104
|
-
* 기본은 ask다.
|
|
228
|
+
* 기본은 ask다. 받아 준 사람은 그 공유가 열려 있는 동안만 기억한다.
|
|
105
229
|
*/
|
|
106
230
|
export type FirstWatchApproval = 'ask' | 'team';
|
|
107
231
|
export declare const DEFAULT_FIRST_WATCH_APPROVAL: FirstWatchApproval;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../../src/peer/protocol.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../../src/peer/protocol.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../../src/peer/protocol.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../../src/peer/protocol.ts"],"names":[],"mappings":"AA8KA,0DAA0D;AAC1D,MAAM,CAAC,MAAM,iBAAiB,GAAG,EAAE,GAAG,IAAI,CAAC;AAO3C,MAAM,CAAC,MAAM,4BAA4B,GAAuB,KAAK,CAAC;AAEtE,wBAAwB;AACxB,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,GAAG,EAAE,CAAC;AAE9C,sCAAsC;AACtC,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC"}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import type { MachineKey } from './keys.js';
|
|
2
|
+
import type { InboxResult } from './inbox.js';
|
|
3
|
+
import type { MirrorFeed } from './mirror.js';
|
|
4
|
+
import type { InboundAnswer, InboundMessage, OwnedShare } from './network.js';
|
|
5
|
+
import type { PeerState } from './state.js';
|
|
6
|
+
/**
|
|
7
|
+
* ges_peer ask_user. 주인 세션 모델이 공유를 보는 팀원에게 묻고 그 사람 기기가 서명한 답을 받는다.
|
|
8
|
+
* 주인 쪽(질문 내기, 답 검사)과 보는 쪽(질문 받기, 답 서명)이 다 여기 있다. 통로와 명단, 승인 기록은
|
|
9
|
+
* PeerNetwork가 들고 있고 이 쪽은 QuestionHost로만 닿는다.
|
|
10
|
+
*/
|
|
11
|
+
/** 한 데몬이 동시에 열어 두는 질문 수 */
|
|
12
|
+
export declare const MAX_OPEN_QUESTIONS = 32;
|
|
13
|
+
/** 질문 시한의 기본값과 범위 */
|
|
14
|
+
export declare const DEFAULT_ASK_TTL_MS: number;
|
|
15
|
+
export declare const MIN_ASK_TTL_MS: number;
|
|
16
|
+
export declare const MAX_ASK_TTL_MS: number;
|
|
17
|
+
/** ges_peer ask_user의 답 */
|
|
18
|
+
export interface AskResult {
|
|
19
|
+
question: string;
|
|
20
|
+
/** 질문이 간 사람 */
|
|
21
|
+
to: string[];
|
|
22
|
+
/** 질문이 간 공유 id */
|
|
23
|
+
shares: string[];
|
|
24
|
+
expiresAt: number;
|
|
25
|
+
}
|
|
26
|
+
/** 질문과 답에 쓰는 봉인 메시지. PeerNetwork의 봉인 종류에 같이 든다 */
|
|
27
|
+
export type QuestionBox =
|
|
28
|
+
/** 주인 → 보는 쪽. 주인 세션 모델의 질문 */
|
|
29
|
+
{
|
|
30
|
+
t: 'ask';
|
|
31
|
+
share: string;
|
|
32
|
+
q: string;
|
|
33
|
+
text: string;
|
|
34
|
+
expiresAt: number;
|
|
35
|
+
}
|
|
36
|
+
/** 주인 → 보는 쪽. 다른 사람이 먼저 답했거나(answered) 시한이 지나(expired) 끝났다 */
|
|
37
|
+
| {
|
|
38
|
+
t: 'ask_close';
|
|
39
|
+
share: string;
|
|
40
|
+
q: string;
|
|
41
|
+
reason: string;
|
|
42
|
+
}
|
|
43
|
+
/** 보는 쪽 → 주인. 뷰어에서 사람이 쓴 답. sig는 answerSignedText에 건 기기 서명이다 */
|
|
44
|
+
| {
|
|
45
|
+
t: 'answer';
|
|
46
|
+
share: string;
|
|
47
|
+
q: string;
|
|
48
|
+
body: string;
|
|
49
|
+
at: number;
|
|
50
|
+
sig: string;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* 주인 → 보는 쪽. 답 상태. reopened는 주인 세션에 넣지 못해 질문을 다시 열었다는 뜻이라 보는 쪽이
|
|
54
|
+
* 다시 답할 수 있다
|
|
55
|
+
*/
|
|
56
|
+
| {
|
|
57
|
+
t: 'answer_status';
|
|
58
|
+
share: string;
|
|
59
|
+
q: string;
|
|
60
|
+
status: AnswerStatus;
|
|
61
|
+
reason?: string;
|
|
62
|
+
reopened?: boolean;
|
|
63
|
+
};
|
|
64
|
+
type AnswerStatus = 'inserted' | 'delivered' | 'rejected';
|
|
65
|
+
/** 주인 쪽에서 본 원격 구독 하나 */
|
|
66
|
+
export interface QuestionSub {
|
|
67
|
+
share: string;
|
|
68
|
+
watcher: string;
|
|
69
|
+
ended: boolean;
|
|
70
|
+
}
|
|
71
|
+
/** 보는 쪽에서 본 원격 공유 하나 */
|
|
72
|
+
export interface QuestionWatch {
|
|
73
|
+
id: string;
|
|
74
|
+
owner: string;
|
|
75
|
+
share: string;
|
|
76
|
+
/** 구독이 열려 있으면 있다 */
|
|
77
|
+
sub?: string;
|
|
78
|
+
feed: MirrorFeed;
|
|
79
|
+
}
|
|
80
|
+
/** 질문과 답이 PeerNetwork에서 빌려 쓰는 것 */
|
|
81
|
+
export interface QuestionHost {
|
|
82
|
+
readonly state: PeerState;
|
|
83
|
+
readonly key: MachineKey;
|
|
84
|
+
sendBox(to: string, msg: QuestionBox): boolean;
|
|
85
|
+
/** 주인 쪽. 지금 열린 원격 구독 */
|
|
86
|
+
subs(): Iterable<QuestionSub>;
|
|
87
|
+
/** 보는 쪽. 보고 있는 원격 공유 */
|
|
88
|
+
watches(): Iterable<QuestionWatch>;
|
|
89
|
+
watch(id: string): QuestionWatch | undefined;
|
|
90
|
+
personOf(machine: string): string;
|
|
91
|
+
machinesOf(person: string): string[];
|
|
92
|
+
/** 이 공유로 이 기기가 보낸 것을 막을 이유(kicked, denied, not_approved). 받으면 undefined */
|
|
93
|
+
refusal(share: string, from: string): string | undefined;
|
|
94
|
+
/** 거절 답과 감사 행 상한. 넘으면 false */
|
|
95
|
+
takeReject(from: string): boolean;
|
|
96
|
+
lookupShare(id: string): OwnedShare | undefined;
|
|
97
|
+
insertInbound(deliver: NonNullable<OwnedShare['deliver']>, inbound: InboundMessage | InboundAnswer, on: {
|
|
98
|
+
inserted(maybeWritten: boolean): void;
|
|
99
|
+
delivered(): void;
|
|
100
|
+
}): Promise<InboxResult>;
|
|
101
|
+
/**
|
|
102
|
+
* 주인 기기에 보낼 봉인을 만든다. 주인이 명단에 없거나 릴레이에 안 붙어 있으면 바로 던진다. 돌려준
|
|
103
|
+
* 함수를 부르면 릴레이 큐에 넣어 보낸다
|
|
104
|
+
*/
|
|
105
|
+
prepareSend(owner: string, msg: QuestionBox): () => Promise<'queued' | 'delivered'>;
|
|
106
|
+
}
|
|
107
|
+
export declare class QuestionDesk {
|
|
108
|
+
private readonly host;
|
|
109
|
+
/** 주인 쪽. 열린 질문. 공유처럼 데몬이 다시 뜨면 사라진다 */
|
|
110
|
+
private open;
|
|
111
|
+
/** 주인 쪽. 닫힌 질문과 닫힌 이유. 늦게 온 답의 거절 이유로 쓴다 */
|
|
112
|
+
private closed;
|
|
113
|
+
/**
|
|
114
|
+
* 보는 쪽. 주인 기기마다 받는 새 질문 수. 질문마다 감사 행과 뷰어 알림이 따른다. 주인 쪽이 열린
|
|
115
|
+
* 질문 32개와 최소 시한 60초를 허용하므로 메시지 수신 한도(10분에 36건)를 쓴다
|
|
116
|
+
*/
|
|
117
|
+
private askLimiter;
|
|
118
|
+
/**
|
|
119
|
+
* 주인 쪽. 같은 기기가 같은 공유(`공유|기기`)에서 인박스에 답을 넣으려는 수를 10분에 36번으로 센다.
|
|
120
|
+
* 인박스가 없는 동안 다시 열린 질문에 계속 답하는 경우를 위해 뒀다. network.test.ts의 "같은 기기가
|
|
121
|
+
* 인박스에 계속 못 넣는 답을 보내면 36번 뒤에 rate_limited로 막는다"가 본다
|
|
122
|
+
*/
|
|
123
|
+
private answerLimiter;
|
|
124
|
+
constructor(host: QuestionHost);
|
|
125
|
+
stop(): void;
|
|
126
|
+
/** 질문과 답 봉인을 받는다. PeerNetwork.onReceive가 넘긴다 */
|
|
127
|
+
receive(from: string, msg: QuestionBox): void;
|
|
128
|
+
/**
|
|
129
|
+
* 주인 쪽: 주인 세션 모델의 질문을 그 세션 공유를 지금 보고 있는 팀원에게 보낸다. to를 주면 그
|
|
130
|
+
* 사람 기기만이다. 구독이 열린 기기만 받으므로 승인 전, 거절, kick된 기기에는 안 간다. 질문
|
|
131
|
+
* 글자는 부르는 쪽이 가린 뒤 넘긴다. 답은 나중에 onAnswer가 받아 주인 세션에 넣는다.
|
|
132
|
+
*/
|
|
133
|
+
ask(shares: string[], raw: string, to: string | undefined, ttlMs: number): AskResult;
|
|
134
|
+
private expireQuestion;
|
|
135
|
+
/** 질문을 끝내고 받은 사람 뷰어에 알린다. except 자리(먼저 답한 기기)에는 안 알린다 */
|
|
136
|
+
private closeQuestion;
|
|
137
|
+
/**
|
|
138
|
+
* 주인 쪽: 답을 검사하고 주인 세션 인박스에 `<peer-answer … verified>`로 넣는다. 검사 순서는
|
|
139
|
+
* 제안서 "ask_user 서명 답" 절의 표와 같다. 하나라도 걸리면 넣지 않는다. network.test.ts의 "ask_user 서명
|
|
140
|
+
* 답" 블록이 kicked, not_approved, not_asked, answered, bad_signature, bad_frame, bad_time, expired, 길이
|
|
141
|
+
* 검사, rate_limited, 인박스 실패 뒤 처리를 넣어 본다.
|
|
142
|
+
*/
|
|
143
|
+
private onAnswer;
|
|
144
|
+
/**
|
|
145
|
+
* 주인 쪽: 답을 넣지 못했다. 질문이 아직 열려 있으면 reopened를 실어 답한 기기가 다시 답하게 한다. 이
|
|
146
|
+
* 알림은 거절 상한을 타지 않는다
|
|
147
|
+
*/
|
|
148
|
+
private reopen;
|
|
149
|
+
/** 보는 쪽: 내가 보는 공유의 주인 데몬이 보낸 질문을 뷰어에 띄운다 */
|
|
150
|
+
private onAsk;
|
|
151
|
+
private onAskClose;
|
|
152
|
+
private onAnswerStatus;
|
|
153
|
+
/**
|
|
154
|
+
* 보는 쪽: 뷰어에서 사람이 쓴 답을 기기 키로 서명해 주인 데몬에 보낸다. 부르는 곳은 lookupWatch가
|
|
155
|
+
* 뷰어에 넘기는 answer 하나다. IPC에 답 요청이 없는 건 network.test.ts의 "IPC와 MCP 도구에는 답을
|
|
156
|
+
* 서명하는 길이 없다"가 본다. 주인 데몬이 오프라인이면 릴레이가 메시지처럼 들고 있는다.
|
|
157
|
+
*/
|
|
158
|
+
answer(watchId: string, question: string, raw: string): Promise<{
|
|
159
|
+
question: string;
|
|
160
|
+
}>;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* 답에 거는 기기 서명의 대상. 질문 id와 공유, 본문, 답한 기기, 시각을 한 덩어리로 묶어 어느 질문에
|
|
164
|
+
* 무엇이라고 답했는지를 그 기기가 보증한다. 봉인 상자의 서명은 통로의 서명이라 따로 둔다.
|
|
165
|
+
*/
|
|
166
|
+
export declare function answerSignedText(share: string, question: string, body: string, device: string, at: number): string;
|
|
167
|
+
export {};
|
|
168
|
+
//# sourceMappingURL=questions.d.ts.map
|