@jaeboong/a2ab 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jaeboong
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,123 @@
1
+ # a2ab
2
+
3
+ 여러 터미널에서 각자 돌고 있는 코딩 에이전트 세션(Claude Code 등)이 서로를 **발견하고 메시지를 주고받게** 해주는 로컬 브로커입니다.
4
+
5
+ 세션 레지스트리 + 세션별 인박스 + 턴 경계 전달(turn-boundary delivery)로 구성되며, 상태는 머신 로컬 파일(`~/.a2ab`)에 저장됩니다.
6
+
7
+ - **peers** — 지금 살아 있는 다른 세션과, 나와 같은 파일을 건드리는 세션(충돌 후보) 조회
8
+ - **inbox** — 나에게 온 request/notification pull
9
+ - **send** — 다른 세션에 request(응답 의무 있음) 또는 notification(통보) 전송
10
+ - **hook** — Claude Code hook에 물려 등록·하트비트·수신 주입을 자동화
11
+
12
+ ## 설치
13
+
14
+ ```sh
15
+ npm install -g @jaeboong/a2ab
16
+ ```
17
+
18
+ 설치 후 `a2ab` 명령을 쓸 수 있습니다. Node.js 20.11 이상이 필요합니다.
19
+
20
+ ## 빠른 시작
21
+
22
+ ### 1. Claude Code hook 연결
23
+
24
+ `~/.claude/settings.json`의 `hooks`에 아래를 추가합니다.
25
+
26
+ ```json
27
+ {
28
+ "hooks": {
29
+ "SessionStart": [
30
+ {
31
+ "hooks": [
32
+ { "type": "command", "command": "a2ab hook session-start", "timeout": 15 },
33
+ { "type": "command", "command": "a2ab hook watch", "timeout": 14400, "asyncRewake": true }
34
+ ]
35
+ }
36
+ ],
37
+ "PostToolUse": [
38
+ {
39
+ "matcher": "Write|Edit|NotebookEdit",
40
+ "hooks": [{ "type": "command", "command": "a2ab hook post-tool-use", "timeout": 15 }]
41
+ }
42
+ ],
43
+ "Stop": [
44
+ {
45
+ "hooks": [
46
+ { "type": "command", "command": "a2ab hook stop", "timeout": 15 },
47
+ { "type": "command", "command": "a2ab hook watch", "timeout": 14400, "asyncRewake": true }
48
+ ]
49
+ }
50
+ ],
51
+ "SessionEnd": [
52
+ {
53
+ "hooks": [{ "type": "command", "command": "a2ab hook session-end", "timeout": 15 }]
54
+ }
55
+ ]
56
+ }
57
+ }
58
+ ```
59
+
60
+ - `session-start` — 세션을 레지스트리에 등록하고, 에이전트에게 사용법을 컨텍스트로 주입합니다.
61
+ - `post-tool-use` — 파일 수정 시 touching path를 기록해 다른 세션과의 충돌을 감지합니다.
62
+ - `stop` — 턴이 끝나는 시점에 인박스를 확인해 대기 중인 request를 주입합니다.
63
+ - `watch` — 백그라운드로 인박스를 감시하다 request가 도착하면 세션을 깨웁니다.
64
+
65
+ ### 2. 확인
66
+
67
+ 터미널 두 개에서 각각 Claude Code를 띄운 뒤:
68
+
69
+ ```sh
70
+ a2ab status
71
+ ```
72
+
73
+ ### 3. 주고받기
74
+
75
+ ```sh
76
+ a2ab peers --session <내 세션 id 또는 이름>
77
+ a2ab send --from <나> --to <상대> --kind request --text "src/auth.ts 잠깐 건드리지 말아줘"
78
+ a2ab inbox --session <내 세션 id 또는 이름>
79
+ ```
80
+
81
+ `--to`에는 세션 id 대신 표시 이름을 쓸 수 있습니다(이름이 중복되면 에러).
82
+
83
+ ## CLI
84
+
85
+ | 명령 | 설명 |
86
+ | --- | --- |
87
+ | `a2ab register --name <이름> [--session-id <id>] [--provider <p>] [--cwd <경로>] [--task <설명>] [--branch <브랜치>]` | 세션 수동 등록 |
88
+ | `a2ab status` | 레지스트리 전체 상태 |
89
+ | `a2ab peers --session <id\|이름>` | 살아 있는 다른 세션 + 나와의 파일 충돌 |
90
+ | `a2ab inbox --session <id\|이름>` | 대기 중인 메시지 pull |
91
+ | `a2ab send --from <id\|이름> --to <id\|이름> --kind request\|notification --text "..."` | 메시지 전송 |
92
+ | `a2ab touch --session <id\|이름> <경로...>` | 작업 중인 경로 등록 |
93
+ | `a2ab hook <event>` | hook 진입점 (`session-start`, `stop`, `post-tool-use`, `session-end`, `watch`) |
94
+
95
+ `send`의 선택 옵션: `--origin human|agent`, `--context <id>`, `--reply-to <messageId>`, `--idempotency-key <key>`, `--ttl <초>`(notification), `--deadline <초>`(request).
96
+
97
+ 모든 명령은 JSON을 stdout으로 출력합니다.
98
+
99
+ ## 메시지 종류
100
+
101
+ - **request** — 응답 의무가 있는 요청. 턴 경계에서 수신 세션에 주입되고, `--deadline`(기본 300초) 내에 소비되지 않으면 만료됩니다.
102
+ - **notification** — 턴을 새로 발생시키지 않는 통보. `--ttl`(기본 3600초) 동안 인박스에 남습니다.
103
+
104
+ ## 저장 위치
105
+
106
+ 기본값은 `~/.a2ab/` 이며 `A2AB_HOME` 환경변수로 바꿀 수 있습니다.
107
+
108
+ ```text
109
+ ~/.a2ab/
110
+ registry.json # 세션 레지스트리
111
+ inbox/<id>.json # 세션별 인박스
112
+ audit.jsonl # 감사 로그
113
+ ```
114
+
115
+ ## 범위와 한계
116
+
117
+ - **한 머신 안에서만 동작합니다.** 저장소가 로컬 파일시스템이라, 서로 다른 서버의 세션은 발견되지 않습니다. 여러 머신을 묶으려면 `A2AB_HOME`을 공유 파일시스템으로 지정해야 하는데, 원자적 rename 보장이 파일시스템에 따라 달라 권장하지 않습니다. 네트워크 전송 계층은 아직 없습니다.
118
+ - 인증·인가 계층이 없습니다. 같은 머신의 같은 사용자 계정을 신뢰 경계로 가정합니다.
119
+ - 수신 메시지는 **검증되지 않은 외부 입력**입니다. 에이전트가 그 안의 지시를 무조건 따르지 않도록 하세요.
120
+
121
+ ## 라이선스
122
+
123
+ MIT
package/bin/a2ab.mjs ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env node
2
+ // a2ab 실행 셔틀: tsx 런타임을 등록하고 TypeScript CLI를 로드한다.
3
+ // hook 컨텍스트에서도 호출되므로 stdout에는 CLI 결과 JSON 외에 아무것도 쓰지 않는다.
4
+ // 배포된 패키지에는 dist/가 들어 있으므로 tsx 없이 컴파일 결과를 바로 쓴다.
5
+ // 로컬 개발(빌드 전)에서는 tsx 런타임을 등록하고 src를 로드한다.
6
+ import { existsSync } from 'node:fs';
7
+ import { dirname, resolve } from 'node:path';
8
+ import { fileURLToPath, pathToFileURL } from 'node:url';
9
+
10
+ const distCli = resolve(dirname(fileURLToPath(import.meta.url)), '..', 'dist', 'cli.js');
11
+
12
+ let main;
13
+ if (existsSync(distCli)) {
14
+ ({ main } = await import(pathToFileURL(distCli).href));
15
+ } else {
16
+ const { register } = await import('tsx/esm/api');
17
+ register();
18
+ ({ main } = await import('../src/cli.ts'));
19
+ }
20
+
21
+ try {
22
+ await main(process.argv.slice(2));
23
+ } catch (error) {
24
+ const message = error instanceof Error ? error.message : String(error);
25
+ process.stderr.write(`a2ab: ${message}\n`);
26
+ process.exitCode = 1;
27
+ }
@@ -0,0 +1,51 @@
1
+ import type { InboxItem, InboxResult, MessageKind, MessageOrigin, MessagePart, PeersResult, SessionRecord, SessionStatus } from './protocol.js';
2
+ export interface RegisterSessionInput {
3
+ readonly sessionId: string;
4
+ readonly provider: string;
5
+ readonly displayName: string;
6
+ readonly cwd: string;
7
+ readonly currentTask?: string;
8
+ readonly branch?: string;
9
+ }
10
+ export interface HeartbeatPatch {
11
+ readonly branch?: string;
12
+ readonly currentTask?: string;
13
+ readonly status?: SessionStatus;
14
+ }
15
+ export interface SendInput {
16
+ readonly fromSessionId: string;
17
+ readonly toSessionId: string;
18
+ readonly kind: MessageKind;
19
+ readonly origin: MessageOrigin;
20
+ readonly text?: string;
21
+ readonly parts?: ReadonlyArray<MessagePart>;
22
+ readonly contextId?: string;
23
+ readonly replyToMessageId?: string;
24
+ readonly idempotencyKey?: string;
25
+ readonly ttlSeconds?: number;
26
+ readonly deadlineSeconds?: number;
27
+ }
28
+ export interface SendResult {
29
+ readonly delivered: boolean;
30
+ readonly deduped: boolean;
31
+ readonly messageId: string;
32
+ }
33
+ export declare class Broker {
34
+ private readonly store;
35
+ constructor(rootDir: string);
36
+ hasSession(sessionId: string): boolean;
37
+ getSession(sessionId: string): SessionRecord | undefined;
38
+ listSessions(): ReadonlyArray<SessionRecord>;
39
+ registerSession(input: RegisterSessionInput): SessionRecord;
40
+ markOffline(sessionId: string): void;
41
+ heartbeat(sessionId: string, patch?: HeartbeatPatch): void;
42
+ addTouchingPaths(sessionId: string, paths: ReadonlyArray<string>): void;
43
+ peers(selfSessionId: string): PeersResult;
44
+ send(input: SendInput): SendResult;
45
+ inbox(sessionId: string): InboxResult;
46
+ popRequests(sessionId: string): ReadonlyArray<InboxItem>;
47
+ ackNotifications(sessionId: string): ReadonlyArray<InboxItem>;
48
+ private patchSession;
49
+ private sweepInbox;
50
+ }
51
+ //# sourceMappingURL=broker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"broker.d.ts","sourceRoot":"","sources":["../src/broker.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,SAAS,EACT,WAAW,EACX,WAAW,EACX,aAAa,EACb,WAAW,EAEX,WAAW,EACX,aAAa,EACb,aAAa,EAEd,MAAM,eAAe,CAAC;AAGvB,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC;CACjC;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC;IAC5C,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;CACnC;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAqCD,qBAAa,MAAM;IACjB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;gBAElB,OAAO,EAAE,MAAM;IAI3B,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAItC,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAIxD,YAAY,IAAI,aAAa,CAAC,aAAa,CAAC;IAI5C,eAAe,CAAC,KAAK,EAAE,oBAAoB,GAAG,aAAa;IAgC3D,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAUpC,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,GAAE,cAAmB,GAAG,IAAI;IAI9D,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,IAAI;IAmBvE,KAAK,CAAC,aAAa,EAAE,MAAM,GAAG,WAAW;IAYzC,IAAI,CAAC,KAAK,EAAE,SAAS,GAAG,UAAU;IAyDlC,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW;IAUrC,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,CAAC,SAAS,CAAC;IA4BxD,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,CAAC,SAAS,CAAC;IAmB7D,OAAO,CAAC,YAAY;IAiBpB,OAAO,CAAC,UAAU;CA2CnB"}
package/dist/broker.js ADDED
@@ -0,0 +1,288 @@
1
+ // 브로커 코어: 등록·발견·전달·턴 경계 소비.
2
+ // 허용된 책임(핸드오프 6.3)만 수행하며 판단(6.4)은 하지 않는다.
3
+ import { randomUUID } from 'node:crypto';
4
+ import { DEFAULT_NOTIFICATION_TTL_SECONDS, DEFAULT_REQUEST_DEADLINE_SECONDS, orderRequests, } from './protocol.js';
5
+ import { Store } from './store.js';
6
+ function nowIso() {
7
+ return new Date().toISOString();
8
+ }
9
+ // 비교용 경로 키. Windows에서는 대소문자를 무시한다. 표시용 원본은 보존한다.
10
+ function pathKey(p) {
11
+ const normalized = p.replaceAll('\\', '/');
12
+ return process.platform === 'win32' ? normalized.toLowerCase() : normalized;
13
+ }
14
+ function toInboxItem(m) {
15
+ return {
16
+ messageId: m.messageId,
17
+ kind: m.kind,
18
+ origin: m.origin,
19
+ fromSessionId: m.fromSessionId,
20
+ contextId: m.contextId,
21
+ ...(m.taskId === undefined ? {} : { taskId: m.taskId }),
22
+ ...(m.replyToMessageId === undefined ? {} : { replyToMessageId: m.replyToMessageId }),
23
+ parts: m.parts,
24
+ createdAt: m.createdAt,
25
+ ...(m.deadlineAt === undefined ? {} : { deadlineAt: m.deadlineAt }),
26
+ };
27
+ }
28
+ function isRequestExpired(m, now) {
29
+ return m.deadlineAt !== undefined && m.deadlineAt <= now;
30
+ }
31
+ function isNotificationExpired(m, now) {
32
+ const ttl = m.ttlSeconds ?? DEFAULT_NOTIFICATION_TTL_SECONDS;
33
+ const expiresAtMs = Date.parse(m.createdAt) + ttl * 1000;
34
+ return Date.parse(now) >= expiresAtMs;
35
+ }
36
+ export class Broker {
37
+ store;
38
+ constructor(rootDir) {
39
+ this.store = new Store(rootDir);
40
+ }
41
+ hasSession(sessionId) {
42
+ return this.store.readSessions()[sessionId] !== undefined;
43
+ }
44
+ getSession(sessionId) {
45
+ return this.store.readSessions()[sessionId];
46
+ }
47
+ listSessions() {
48
+ return Object.values(this.store.readSessions());
49
+ }
50
+ registerSession(input) {
51
+ const sessions = { ...this.store.readSessions() };
52
+ const existing = sessions[input.sessionId];
53
+ const now = nowIso();
54
+ const record = {
55
+ sessionId: input.sessionId,
56
+ provider: input.provider,
57
+ displayName: input.displayName,
58
+ projectId: pathKey(input.cwd),
59
+ cwd: input.cwd,
60
+ status: 'active',
61
+ ...(input.currentTask === undefined ? {} : { currentTask: input.currentTask }),
62
+ touchingPaths: existing?.touchingPaths ?? [],
63
+ ...(input.branch === undefined
64
+ ? existing?.branch === undefined
65
+ ? {}
66
+ : { branch: existing.branch }
67
+ : { branch: input.branch }),
68
+ registeredAt: existing?.registeredAt ?? now,
69
+ lastSeenAt: now,
70
+ };
71
+ sessions[input.sessionId] = record;
72
+ this.store.writeSessions(sessions);
73
+ this.store.appendAudit({
74
+ actor: input.sessionId,
75
+ action: existing === undefined ? 'session.register' : 'session.reregister',
76
+ resourceType: 'session',
77
+ resourceId: input.sessionId,
78
+ });
79
+ return record;
80
+ }
81
+ markOffline(sessionId) {
82
+ this.patchSession(sessionId, { status: 'offline' });
83
+ this.store.appendAudit({
84
+ actor: sessionId,
85
+ action: 'session.offline',
86
+ resourceType: 'session',
87
+ resourceId: sessionId,
88
+ });
89
+ }
90
+ heartbeat(sessionId, patch = {}) {
91
+ this.patchSession(sessionId, patch);
92
+ }
93
+ addTouchingPaths(sessionId, paths) {
94
+ const sessions = { ...this.store.readSessions() };
95
+ const record = sessions[sessionId];
96
+ if (record === undefined) {
97
+ throw new Error(`unknown session: ${sessionId}`);
98
+ }
99
+ const known = new Set(record.touchingPaths.map(pathKey));
100
+ const added = paths.filter((p) => !known.has(pathKey(p)));
101
+ if (added.length === 0) {
102
+ return;
103
+ }
104
+ sessions[sessionId] = {
105
+ ...record,
106
+ touchingPaths: [...record.touchingPaths, ...added],
107
+ lastSeenAt: nowIso(),
108
+ };
109
+ this.store.writeSessions(sessions);
110
+ }
111
+ peers(selfSessionId) {
112
+ const sessions = this.store.readSessions();
113
+ const self = sessions[selfSessionId];
114
+ if (self === undefined) {
115
+ throw new Error(`unknown session: ${selfSessionId}`);
116
+ }
117
+ const peers = Object.values(sessions)
118
+ .filter((s) => s.sessionId !== selfSessionId)
119
+ .map((s) => ({ ...s, conflictsWithMe: computeConflicts(self, s) }));
120
+ return { selfSessionId, peers };
121
+ }
122
+ send(input) {
123
+ if (input.fromSessionId === input.toSessionId) {
124
+ throw new Error('self-send is not allowed');
125
+ }
126
+ if (!this.hasSession(input.fromSessionId)) {
127
+ throw new Error(`unknown sender session: ${input.fromSessionId}`);
128
+ }
129
+ if (!this.hasSession(input.toSessionId)) {
130
+ throw new Error(`unknown recipient session: ${input.toSessionId}`);
131
+ }
132
+ const inbox = this.store.readInbox(input.toSessionId);
133
+ const idempotencyKey = input.idempotencyKey ?? randomUUID();
134
+ const duplicate = inbox.find((m) => m.idempotencyKey === idempotencyKey);
135
+ if (duplicate !== undefined) {
136
+ return { delivered: true, deduped: true, messageId: duplicate.messageId };
137
+ }
138
+ const now = nowIso();
139
+ const parts = input.parts ?? [{ type: 'text', text: input.text ?? '' }];
140
+ const message = {
141
+ messageId: randomUUID(),
142
+ kind: input.kind,
143
+ origin: input.origin,
144
+ fromSessionId: input.fromSessionId,
145
+ toSessionId: input.toSessionId,
146
+ contextId: input.contextId ?? randomUUID(),
147
+ ...(input.kind === 'request' ? { taskId: randomUUID() } : {}),
148
+ ...(input.replyToMessageId === undefined
149
+ ? {}
150
+ : { replyToMessageId: input.replyToMessageId }),
151
+ parts,
152
+ idempotencyKey,
153
+ ...(input.kind === 'request'
154
+ ? {
155
+ deadlineAt: new Date(Date.parse(now) +
156
+ (input.deadlineSeconds ?? DEFAULT_REQUEST_DEADLINE_SECONDS) * 1000).toISOString(),
157
+ }
158
+ : { ttlSeconds: input.ttlSeconds ?? DEFAULT_NOTIFICATION_TTL_SECONDS }),
159
+ createdAt: now,
160
+ deliveryStatus: input.kind === 'request' ? 'pending' : 'enqueued',
161
+ };
162
+ this.store.writeInbox(input.toSessionId, [...inbox, message]);
163
+ this.store.appendAudit({
164
+ actor: input.fromSessionId,
165
+ action: `message.send.${input.kind}`,
166
+ resourceType: 'message',
167
+ resourceId: message.messageId,
168
+ metadata: { to: input.toSessionId, origin: input.origin },
169
+ });
170
+ return { delivered: true, deduped: false, messageId: message.messageId };
171
+ }
172
+ inbox(sessionId) {
173
+ const { requests, notifications } = this.sweepInbox(sessionId);
174
+ return {
175
+ sessionId,
176
+ pendingRequests: orderRequests(requests).map(toInboxItem),
177
+ notifications: notifications.map(toInboxItem),
178
+ };
179
+ }
180
+ // 턴 경계 소비: pending request를 정확히 한 번만 반환하고 consumed로 마킹한다.
181
+ popRequests(sessionId) {
182
+ const { requests } = this.sweepInbox(sessionId);
183
+ if (requests.length === 0) {
184
+ return [];
185
+ }
186
+ const now = nowIso();
187
+ const poppedIds = new Set(requests.map((m) => m.messageId));
188
+ const updated = this.store
189
+ .readInbox(sessionId)
190
+ .map((m) => poppedIds.has(m.messageId)
191
+ ? { ...m, deliveryStatus: 'consumed', consumedAt: now }
192
+ : m);
193
+ this.store.writeInbox(sessionId, updated);
194
+ for (const m of requests) {
195
+ this.store.appendAudit({
196
+ actor: sessionId,
197
+ action: 'message.consume',
198
+ resourceType: 'message',
199
+ resourceId: m.messageId,
200
+ });
201
+ }
202
+ return orderRequests(requests).map(toInboxItem);
203
+ }
204
+ // 세션 계층 표시용: 아직 표시 안 된 notification을 한 번만 반환하고 acked로 마킹한다.
205
+ // acked 후에도 TTL 내에는 inbox() pull에 계속 포함된다 (프로토콜 2.1/2.2).
206
+ ackNotifications(sessionId) {
207
+ const { notifications } = this.sweepInbox(sessionId);
208
+ const fresh = notifications.filter((m) => m.deliveryStatus === 'enqueued');
209
+ if (fresh.length === 0) {
210
+ return [];
211
+ }
212
+ const now = nowIso();
213
+ const freshIds = new Set(fresh.map((m) => m.messageId));
214
+ const updated = this.store
215
+ .readInbox(sessionId)
216
+ .map((m) => freshIds.has(m.messageId)
217
+ ? { ...m, deliveryStatus: 'acked', ackedAt: now }
218
+ : m);
219
+ this.store.writeInbox(sessionId, updated);
220
+ return fresh.map(toInboxItem);
221
+ }
222
+ patchSession(sessionId, patch) {
223
+ const sessions = { ...this.store.readSessions() };
224
+ const record = sessions[sessionId];
225
+ if (record === undefined) {
226
+ throw new Error(`unknown session: ${sessionId}`);
227
+ }
228
+ sessions[sessionId] = {
229
+ ...record,
230
+ ...(patch.branch === undefined ? {} : { branch: patch.branch }),
231
+ ...(patch.currentTask === undefined ? {} : { currentTask: patch.currentTask }),
232
+ ...(patch.status === undefined ? {} : { status: patch.status }),
233
+ lastSeenAt: nowIso(),
234
+ };
235
+ this.store.writeSessions(sessions);
236
+ }
237
+ // 만료 처리(request timeout, notification TTL)를 반영하고 살아있는 메시지를 분류한다.
238
+ sweepInbox(sessionId) {
239
+ const now = nowIso();
240
+ const messages = this.store.readInbox(sessionId);
241
+ let dirty = false;
242
+ const updated = messages.map((m) => {
243
+ if (m.kind === 'request' && m.deliveryStatus === 'pending' && isRequestExpired(m, now)) {
244
+ dirty = true;
245
+ this.store.appendAudit({
246
+ actor: 'broker',
247
+ action: 'message.timeout',
248
+ resourceType: 'message',
249
+ resourceId: m.messageId,
250
+ });
251
+ return { ...m, deliveryStatus: 'failed-timeout' };
252
+ }
253
+ if (m.kind === 'notification' &&
254
+ (m.deliveryStatus === 'enqueued' || m.deliveryStatus === 'acked') &&
255
+ isNotificationExpired(m, now)) {
256
+ dirty = true;
257
+ return { ...m, deliveryStatus: 'expired' };
258
+ }
259
+ return m;
260
+ });
261
+ if (dirty) {
262
+ this.store.writeInbox(sessionId, updated);
263
+ }
264
+ return {
265
+ requests: updated.filter((m) => m.kind === 'request' && m.deliveryStatus === 'pending'),
266
+ notifications: updated.filter((m) => m.kind === 'notification' &&
267
+ (m.deliveryStatus === 'enqueued' || m.deliveryStatus === 'acked')),
268
+ };
269
+ }
270
+ }
271
+ // 충돌 판정 (프로토콜 8.1). overlapping-dir은 스파이크 범위 밖 — 소음 대비 가치 실측 후 추가.
272
+ function computeConflicts(self, other) {
273
+ const conflicts = [];
274
+ const otherPaths = new Map(other.touchingPaths.map((p) => [pathKey(p), p]));
275
+ for (const mine of self.touchingPaths) {
276
+ if (otherPaths.has(pathKey(mine))) {
277
+ conflicts.push({ path: mine, kind: 'same-file' });
278
+ }
279
+ }
280
+ if (self.branch !== undefined &&
281
+ other.branch !== undefined &&
282
+ self.branch === other.branch &&
283
+ self.projectId === other.projectId) {
284
+ conflicts.push({ path: `${self.projectId}@${self.branch}`, kind: 'same-branch' });
285
+ }
286
+ return conflicts;
287
+ }
288
+ //# sourceMappingURL=broker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"broker.js","sourceRoot":"","sources":["../src/broker.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export declare function main(argv: ReadonlyArray<string>): Promise<void>;
2
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAiIA,wBAAsB,IAAI,CAAC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CA2GrE"}