agent-relay 0.1.0 → 1.0.1
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/README.md +56 -730
- package/dist/cli/index.d.ts +6 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +109 -1521
- package/dist/cli/index.js.map +1 -1
- package/dist/daemon/connection.d.ts.map +1 -1
- package/dist/daemon/connection.js +1 -2
- package/dist/daemon/connection.js.map +1 -1
- package/dist/daemon/server.d.ts +14 -1
- package/dist/daemon/server.d.ts.map +1 -1
- package/dist/daemon/server.js +48 -7
- package/dist/daemon/server.js.map +1 -1
- package/dist/dashboard/server.d.ts.map +1 -1
- package/dist/dashboard/server.js +27 -8
- package/dist/dashboard/server.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/storage/adapter.d.ts +43 -0
- package/dist/storage/adapter.d.ts.map +1 -1
- package/dist/storage/adapter.js +106 -1
- package/dist/storage/adapter.js.map +1 -1
- package/dist/storage/sqlite-adapter.d.ts +1 -0
- package/dist/storage/sqlite-adapter.d.ts.map +1 -1
- package/dist/storage/sqlite-adapter.js +29 -0
- package/dist/storage/sqlite-adapter.js.map +1 -1
- package/dist/utils/project-namespace.d.ts +46 -0
- package/dist/utils/project-namespace.d.ts.map +1 -0
- package/dist/utils/project-namespace.js +111 -0
- package/dist/utils/project-namespace.js.map +1 -0
- package/dist/wrapper/client.d.ts +1 -1
- package/dist/wrapper/client.d.ts.map +1 -1
- package/dist/wrapper/client.js +1 -1
- package/dist/wrapper/client.js.map +1 -1
- package/dist/wrapper/index.d.ts +0 -1
- package/dist/wrapper/index.d.ts.map +1 -1
- package/dist/wrapper/index.js +2 -3
- package/dist/wrapper/index.js.map +1 -1
- package/dist/wrapper/tmux-wrapper.d.ts +5 -0
- package/dist/wrapper/tmux-wrapper.d.ts.map +1 -1
- package/dist/wrapper/tmux-wrapper.js +96 -21
- package/dist/wrapper/tmux-wrapper.js.map +1 -1
- package/docs/AGENTS.md +386 -0
- package/docs/CLI-SIMPLIFICATION-COMPLETE.md +48 -0
- package/docs/CONTRIBUTING.md +151 -0
- package/docs/TMUX_IMPLEMENTATION_NOTES.md +364 -0
- package/docs/removable-code-analysis.md +24 -0
- package/install.sh +10 -2
- package/package.json +3 -4
- package/dist/games/index.d.ts +0 -2
- package/dist/games/index.d.ts.map +0 -1
- package/dist/games/index.js +0 -2
- package/dist/games/index.js.map +0 -1
- package/dist/games/tictactoe.d.ts +0 -24
- package/dist/games/tictactoe.d.ts.map +0 -1
- package/dist/games/tictactoe.js +0 -160
- package/dist/games/tictactoe.js.map +0 -1
- package/dist/supervisor/inbox.d.ts +0 -38
- package/dist/supervisor/inbox.d.ts.map +0 -1
- package/dist/supervisor/inbox.js +0 -162
- package/dist/supervisor/inbox.js.map +0 -1
- package/dist/supervisor/index.d.ts +0 -10
- package/dist/supervisor/index.d.ts.map +0 -1
- package/dist/supervisor/index.js +0 -10
- package/dist/supervisor/index.js.map +0 -1
- package/dist/supervisor/spawner.d.ts +0 -54
- package/dist/supervisor/spawner.d.ts.map +0 -1
- package/dist/supervisor/spawner.js +0 -282
- package/dist/supervisor/spawner.js.map +0 -1
- package/dist/supervisor/state.d.ts +0 -132
- package/dist/supervisor/state.d.ts.map +0 -1
- package/dist/supervisor/state.js +0 -465
- package/dist/supervisor/state.js.map +0 -1
- package/dist/supervisor/supervisor.d.ts +0 -67
- package/dist/supervisor/supervisor.d.ts.map +0 -1
- package/dist/supervisor/supervisor.js +0 -263
- package/dist/supervisor/supervisor.js.map +0 -1
- package/dist/supervisor/types.d.ts +0 -139
- package/dist/supervisor/types.d.ts.map +0 -1
- package/dist/supervisor/types.js +0 -12
- package/dist/supervisor/types.js.map +0 -1
- package/dist/webhook/spawner.d.ts +0 -79
- package/dist/webhook/spawner.d.ts.map +0 -1
- package/dist/webhook/spawner.js +0 -288
- package/dist/webhook/spawner.js.map +0 -1
- package/dist/wrapper/pty-wrapper.d.ts +0 -125
- package/dist/wrapper/pty-wrapper.d.ts.map +0 -1
- package/dist/wrapper/pty-wrapper.js +0 -494
- package/dist/wrapper/pty-wrapper.js.map +0 -1
- /package/{CHANGELOG.md → docs/CHANGELOG.md} +0 -0
- /package/{PROTOCOL.md → docs/PROTOCOL.md} +0 -0
package/dist/games/tictactoe.js
DELETED
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tic-Tac-Toe Setup Helpers
|
|
3
|
-
*
|
|
4
|
-
* This is a lightweight “game module” focused on generating instructions and
|
|
5
|
-
* directory setup for manual or scripted agent runs.
|
|
6
|
-
*
|
|
7
|
-
* It intentionally does NOT spawn agent processes (that stays in CLI tooling),
|
|
8
|
-
* and it uses the inbox CLI commands (`inbox-poll`, `inbox-write`) so it works
|
|
9
|
-
* with any agent runtime.
|
|
10
|
-
*/
|
|
11
|
-
import fs from 'node:fs';
|
|
12
|
-
import path from 'node:path';
|
|
13
|
-
function instructionsForPlayerX(dataDir, playerX, playerO) {
|
|
14
|
-
return `# Tic-Tac-Toe Autonomous Game Protocol
|
|
15
|
-
|
|
16
|
-
You are **${playerX}** (X). You play FIRST. Your opponent is **${playerO}** (O).
|
|
17
|
-
|
|
18
|
-
## Board Positions
|
|
19
|
-
\`\`\`
|
|
20
|
-
1 | 2 | 3
|
|
21
|
-
-----------
|
|
22
|
-
4 | 5 | 6
|
|
23
|
-
-----------
|
|
24
|
-
7 | 8 | 9
|
|
25
|
-
\`\`\`
|
|
26
|
-
|
|
27
|
-
## Commands Available
|
|
28
|
-
You have these \`agent-relay\` commands to communicate:
|
|
29
|
-
|
|
30
|
-
**Wait for opponent's message (blocking):**
|
|
31
|
-
\`\`\`bash
|
|
32
|
-
agent-relay inbox-poll -n ${playerX} -d ${dataDir} --clear
|
|
33
|
-
\`\`\`
|
|
34
|
-
|
|
35
|
-
**Send a move to opponent:**
|
|
36
|
-
\`\`\`bash
|
|
37
|
-
agent-relay inbox-write -t ${playerO} -f ${playerX} -m "MOVE: X at position N" -d ${dataDir}
|
|
38
|
-
\`\`\`
|
|
39
|
-
|
|
40
|
-
## PROTOCOL (follow EXACTLY)
|
|
41
|
-
|
|
42
|
-
### Since you're X, you go FIRST:
|
|
43
|
-
1. Make your first move to position 5 (center)
|
|
44
|
-
2. Send it to opponent:
|
|
45
|
-
\`\`\`bash
|
|
46
|
-
agent-relay inbox-write -t ${playerO} -f ${playerX} -m "MOVE: X at position 5" -d ${dataDir}
|
|
47
|
-
\`\`\`
|
|
48
|
-
|
|
49
|
-
### Then enter the game loop:
|
|
50
|
-
1. **WAIT** for opponent's response (this will block until they respond):
|
|
51
|
-
\`\`\`bash
|
|
52
|
-
agent-relay inbox-poll -n ${playerX} -d ${dataDir} --clear
|
|
53
|
-
\`\`\`
|
|
54
|
-
|
|
55
|
-
2. **UPDATE** your mental board state with opponent's move
|
|
56
|
-
|
|
57
|
-
3. **CHECK** for win/draw. If game over, send result and announce:
|
|
58
|
-
\`\`\`bash
|
|
59
|
-
agent-relay inbox-write -t ${playerO} -f ${playerX} -m "GAME OVER: X wins!" -d ${dataDir}
|
|
60
|
-
\`\`\`
|
|
61
|
-
|
|
62
|
-
4. **MAKE** your next move and send it:
|
|
63
|
-
\`\`\`bash
|
|
64
|
-
agent-relay inbox-write -t ${playerO} -f ${playerX} -m "MOVE: X at position N" -d ${dataDir}
|
|
65
|
-
\`\`\`
|
|
66
|
-
|
|
67
|
-
5. **REPEAT** from step 1 until game over
|
|
68
|
-
|
|
69
|
-
## Rules
|
|
70
|
-
- Valid moves: positions 1-9 that are empty
|
|
71
|
-
- Win: 3 in a row (horizontal, vertical, or diagonal)
|
|
72
|
-
- Draw: all 9 positions filled with no winner
|
|
73
|
-
|
|
74
|
-
## CRITICAL
|
|
75
|
-
- NEVER stop mid-game
|
|
76
|
-
- ALWAYS use the inbox-poll command to wait (it blocks until opponent responds)
|
|
77
|
-
- Keep track of the board state
|
|
78
|
-
- Announce result when game ends
|
|
79
|
-
|
|
80
|
-
## START NOW
|
|
81
|
-
Make your FIRST MOVE to position 5, then wait for opponent's response.
|
|
82
|
-
`;
|
|
83
|
-
}
|
|
84
|
-
function instructionsForPlayerO(dataDir, playerX, playerO) {
|
|
85
|
-
return `# Tic-Tac-Toe Autonomous Game Protocol
|
|
86
|
-
|
|
87
|
-
You are **${playerO}** (O). ${playerX} plays first, so you WAIT for their move.
|
|
88
|
-
|
|
89
|
-
## Board Positions
|
|
90
|
-
\`\`\`
|
|
91
|
-
1 | 2 | 3
|
|
92
|
-
-----------
|
|
93
|
-
4 | 5 | 6
|
|
94
|
-
-----------
|
|
95
|
-
7 | 8 | 9
|
|
96
|
-
\`\`\`
|
|
97
|
-
|
|
98
|
-
## Commands Available
|
|
99
|
-
You have these \`agent-relay\` commands to communicate:
|
|
100
|
-
|
|
101
|
-
**Wait for opponent's message (blocking):**
|
|
102
|
-
\`\`\`bash
|
|
103
|
-
agent-relay inbox-poll -n ${playerO} -d ${dataDir} --clear
|
|
104
|
-
\`\`\`
|
|
105
|
-
|
|
106
|
-
**Send a move to opponent:**
|
|
107
|
-
\`\`\`bash
|
|
108
|
-
agent-relay inbox-write -t ${playerX} -f ${playerO} -m "MOVE: O at position N" -d ${dataDir}
|
|
109
|
-
\`\`\`
|
|
110
|
-
|
|
111
|
-
## PROTOCOL (follow EXACTLY)
|
|
112
|
-
|
|
113
|
-
### Since you're O, you go SECOND. Start by waiting:
|
|
114
|
-
1. **WAIT** for opponent's first move (this will block until they move):
|
|
115
|
-
\`\`\`bash
|
|
116
|
-
agent-relay inbox-poll -n ${playerO} -d ${dataDir} --clear
|
|
117
|
-
\`\`\`
|
|
118
|
-
|
|
119
|
-
2. **UPDATE** your mental board state with opponent's move
|
|
120
|
-
|
|
121
|
-
3. **CHECK** for win/draw. If game over, announce result.
|
|
122
|
-
|
|
123
|
-
4. **MAKE** your response move and send it:
|
|
124
|
-
\`\`\`bash
|
|
125
|
-
agent-relay inbox-write -t ${playerX} -f ${playerO} -m "MOVE: O at position N" -d ${dataDir}
|
|
126
|
-
\`\`\`
|
|
127
|
-
|
|
128
|
-
5. **WAIT** for opponent's next move (back to step 1)
|
|
129
|
-
|
|
130
|
-
## Rules
|
|
131
|
-
- Valid moves: positions 1-9 that are empty
|
|
132
|
-
- Win: 3 in a row (horizontal, vertical, or diagonal)
|
|
133
|
-
- Draw: all 9 positions filled with no winner
|
|
134
|
-
|
|
135
|
-
## CRITICAL
|
|
136
|
-
- NEVER stop mid-game
|
|
137
|
-
- ALWAYS use the inbox-poll command to wait (it blocks until opponent responds)
|
|
138
|
-
- Keep track of the board state
|
|
139
|
-
- Announce result when game ends
|
|
140
|
-
|
|
141
|
-
## START NOW
|
|
142
|
-
Run the inbox-poll command to WAIT for ${playerX}'s first move.
|
|
143
|
-
`;
|
|
144
|
-
}
|
|
145
|
-
export function setupTicTacToe(options) {
|
|
146
|
-
const dataDir = options.dataDir;
|
|
147
|
-
const playerX = options.playerX ?? 'PlayerX';
|
|
148
|
-
const playerO = options.playerO ?? 'PlayerO';
|
|
149
|
-
fs.mkdirSync(path.join(dataDir, playerX), { recursive: true });
|
|
150
|
-
fs.mkdirSync(path.join(dataDir, playerO), { recursive: true });
|
|
151
|
-
// Clear inboxes
|
|
152
|
-
fs.writeFileSync(path.join(dataDir, playerX, 'inbox.md'), '', 'utf-8');
|
|
153
|
-
fs.writeFileSync(path.join(dataDir, playerO, 'inbox.md'), '', 'utf-8');
|
|
154
|
-
const instructionsXPath = path.join(dataDir, playerX, 'GAME_INSTRUCTIONS.md');
|
|
155
|
-
const instructionsOPath = path.join(dataDir, playerO, 'GAME_INSTRUCTIONS.md');
|
|
156
|
-
fs.writeFileSync(instructionsXPath, instructionsForPlayerX(dataDir, playerX, playerO), 'utf-8');
|
|
157
|
-
fs.writeFileSync(instructionsOPath, instructionsForPlayerO(dataDir, playerX, playerO), 'utf-8');
|
|
158
|
-
return { dataDir, playerX, playerO, instructionsXPath, instructionsOPath };
|
|
159
|
-
}
|
|
160
|
-
//# sourceMappingURL=tictactoe.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tictactoe.js","sourceRoot":"","sources":["../../src/games/tictactoe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAgB7B,SAAS,sBAAsB,CAAC,OAAe,EAAE,OAAe,EAAE,OAAe;IAC/E,OAAO;;YAEG,OAAO,8CAA8C,OAAO;;;;;;;;;;;;;;;;4BAgB5C,OAAO,OAAO,OAAO;;;;;6BAKpB,OAAO,OAAO,OAAO,kCAAkC,OAAO;;;;;;;;;gCAS3D,OAAO,OAAO,OAAO,kCAAkC,OAAO;;;;;;+BAM/D,OAAO,OAAO,OAAO;;;;;;;gCAOpB,OAAO,OAAO,OAAO,+BAA+B,OAAO;;;;;gCAK3D,OAAO,OAAO,OAAO,kCAAkC,OAAO;;;;;;;;;;;;;;;;;;CAkB7F,CAAC;AACF,CAAC;AAED,SAAS,sBAAsB,CAAC,OAAe,EAAE,OAAe,EAAE,OAAe;IAC/E,OAAO;;YAEG,OAAO,WAAW,OAAO;;;;;;;;;;;;;;;;4BAgBT,OAAO,OAAO,OAAO;;;;;6BAKpB,OAAO,OAAO,OAAO,kCAAkC,OAAO;;;;;;;;+BAQ5D,OAAO,OAAO,OAAO;;;;;;;;;gCASpB,OAAO,OAAO,OAAO,kCAAkC,OAAO;;;;;;;;;;;;;;;;;yCAiBrD,OAAO;CAC/C,CAAC;AACF,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,OAA8B;IAC3D,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAChC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,SAAS,CAAC;IAC7C,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,SAAS,CAAC;IAE7C,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/D,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE/D,gBAAgB;IAChB,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;IACvE,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;IAEvE,MAAM,iBAAiB,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,sBAAsB,CAAC,CAAC;IAC9E,MAAM,iBAAiB,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,sBAAsB,CAAC,CAAC;IAE9E,EAAE,CAAC,aAAa,CAAC,iBAAiB,EAAE,sBAAsB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,CAAC;IAChG,EAAE,CAAC,aAAa,CAAC,iBAAiB,EAAE,sBAAsB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,CAAC;IAEhG,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,CAAC;AAC7E,CAAC"}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Supervisor Inbox Utilities
|
|
3
|
-
*
|
|
4
|
-
* Provides an atomic "claim" for an agent inbox file to avoid losing messages
|
|
5
|
-
* that arrive while the supervisor is processing.
|
|
6
|
-
*/
|
|
7
|
-
export interface InboxMessage {
|
|
8
|
-
from: string;
|
|
9
|
-
timestamp: string;
|
|
10
|
-
body: string;
|
|
11
|
-
}
|
|
12
|
-
export interface ClaimedInbox {
|
|
13
|
-
inboxPath: string;
|
|
14
|
-
processingPath: string;
|
|
15
|
-
content: string;
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Parse inbox markdown into structured messages.
|
|
19
|
-
*
|
|
20
|
-
* Expected format (repeated blocks):
|
|
21
|
-
* ## Message from <sender> | <timestamp>
|
|
22
|
-
* <body>
|
|
23
|
-
*/
|
|
24
|
-
export declare function parseInboxMarkdown(content: string): InboxMessage[];
|
|
25
|
-
/**
|
|
26
|
-
* Atomically claim an inbox by renaming it to a processing file.
|
|
27
|
-
* New incoming messages will be written to a new inbox.md.
|
|
28
|
-
*/
|
|
29
|
-
export declare function claimInbox(inboxPath: string): ClaimedInbox | null;
|
|
30
|
-
/**
|
|
31
|
-
* Finalize a claimed inbox.
|
|
32
|
-
*
|
|
33
|
-
* - On success: delete processing file.
|
|
34
|
-
* - On failure: re-queue the claimed content back into inbox.md without
|
|
35
|
-
* overwriting any messages that arrived while processing.
|
|
36
|
-
*/
|
|
37
|
-
export declare function finalizeClaim(claim: ClaimedInbox, success: boolean): void;
|
|
38
|
-
//# sourceMappingURL=inbox.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"inbox.d.ts","sourceRoot":"","sources":["../../src/supervisor/inbox.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;CACjB;AAeD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,EAAE,CA4DlE;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAyBjE;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CA6CzE"}
|
package/dist/supervisor/inbox.js
DELETED
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Supervisor Inbox Utilities
|
|
3
|
-
*
|
|
4
|
-
* Provides an atomic "claim" for an agent inbox file to avoid losing messages
|
|
5
|
-
* that arrive while the supervisor is processing.
|
|
6
|
-
*/
|
|
7
|
-
import fs from 'node:fs';
|
|
8
|
-
import path from 'node:path';
|
|
9
|
-
// Supported inbox formats:
|
|
10
|
-
// 1) New canonical:
|
|
11
|
-
// ## Message from <sender> | <iso>
|
|
12
|
-
// <body>
|
|
13
|
-
//
|
|
14
|
-
// 2) Legacy (from early inbox-write):
|
|
15
|
-
// ## Message from <sender>
|
|
16
|
-
// **Time:** <iso>
|
|
17
|
-
// <body>
|
|
18
|
-
const MESSAGE_HEADER_V1 = /^## Message from (.+?) \| (.+?)$/gm;
|
|
19
|
-
const MESSAGE_HEADER_LEGACY = /^## Message from (.+?)$/gm;
|
|
20
|
-
const LEGACY_TIME_LINE = /^\*\*Time:\*\*\s*(.+?)\s*$/m;
|
|
21
|
-
/**
|
|
22
|
-
* Parse inbox markdown into structured messages.
|
|
23
|
-
*
|
|
24
|
-
* Expected format (repeated blocks):
|
|
25
|
-
* ## Message from <sender> | <timestamp>
|
|
26
|
-
* <body>
|
|
27
|
-
*/
|
|
28
|
-
export function parseInboxMarkdown(content) {
|
|
29
|
-
const matches = [];
|
|
30
|
-
let m;
|
|
31
|
-
// eslint-disable-next-line no-cond-assign
|
|
32
|
-
while ((m = MESSAGE_HEADER_V1.exec(content)) !== null) {
|
|
33
|
-
matches.push({
|
|
34
|
-
index: m.index,
|
|
35
|
-
from: (m[1] ?? '').trim(),
|
|
36
|
-
timestamp: (m[2] ?? '').trim(),
|
|
37
|
-
headerLen: m[0].length,
|
|
38
|
-
isLegacy: false,
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
// If no canonical headers, try legacy headers.
|
|
42
|
-
if (matches.length === 0) {
|
|
43
|
-
// eslint-disable-next-line no-cond-assign
|
|
44
|
-
while ((m = MESSAGE_HEADER_LEGACY.exec(content)) !== null) {
|
|
45
|
-
matches.push({
|
|
46
|
-
index: m.index,
|
|
47
|
-
from: (m[1] ?? '').trim(),
|
|
48
|
-
timestamp: '',
|
|
49
|
-
headerLen: m[0].length,
|
|
50
|
-
isLegacy: true,
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
if (matches.length === 0)
|
|
55
|
-
return [];
|
|
56
|
-
const messages = [];
|
|
57
|
-
for (let i = 0; i < matches.length; i++) {
|
|
58
|
-
const cur = matches[i];
|
|
59
|
-
const next = matches[i + 1];
|
|
60
|
-
const bodyStart = cur.index + cur.headerLen;
|
|
61
|
-
const bodyEnd = next ? next.index : content.length;
|
|
62
|
-
let bodyChunk = content.substring(bodyStart, bodyEnd).replace(/^\s*\n/, '');
|
|
63
|
-
let timestamp = cur.timestamp;
|
|
64
|
-
if (cur.isLegacy) {
|
|
65
|
-
const t = bodyChunk.match(LEGACY_TIME_LINE);
|
|
66
|
-
if (t?.[1]) {
|
|
67
|
-
timestamp = t[1].trim();
|
|
68
|
-
// Remove the time line from the body
|
|
69
|
-
bodyChunk = bodyChunk.replace(LEGACY_TIME_LINE, '').replace(/^\s*\n/, '');
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
const body = bodyChunk.trim();
|
|
73
|
-
if (!cur.from)
|
|
74
|
-
continue;
|
|
75
|
-
if (!timestamp)
|
|
76
|
-
timestamp = new Date().toISOString();
|
|
77
|
-
if (!body)
|
|
78
|
-
continue;
|
|
79
|
-
messages.push({ from: cur.from, timestamp, body });
|
|
80
|
-
}
|
|
81
|
-
return messages;
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* Atomically claim an inbox by renaming it to a processing file.
|
|
85
|
-
* New incoming messages will be written to a new inbox.md.
|
|
86
|
-
*/
|
|
87
|
-
export function claimInbox(inboxPath) {
|
|
88
|
-
if (!fs.existsSync(inboxPath))
|
|
89
|
-
return null;
|
|
90
|
-
const dir = path.dirname(inboxPath);
|
|
91
|
-
const processingPath = path.join(dir, 'inbox.processing.md');
|
|
92
|
-
try {
|
|
93
|
-
fs.renameSync(inboxPath, processingPath);
|
|
94
|
-
}
|
|
95
|
-
catch (err) {
|
|
96
|
-
const code = err.code;
|
|
97
|
-
// If someone else claimed it or it disappeared, treat as no work.
|
|
98
|
-
if (code === 'ENOENT' || code === 'EACCES' || code === 'EBUSY') {
|
|
99
|
-
return null;
|
|
100
|
-
}
|
|
101
|
-
throw err;
|
|
102
|
-
}
|
|
103
|
-
let content = '';
|
|
104
|
-
try {
|
|
105
|
-
content = fs.readFileSync(processingPath, 'utf-8');
|
|
106
|
-
}
|
|
107
|
-
catch {
|
|
108
|
-
content = '';
|
|
109
|
-
}
|
|
110
|
-
return { inboxPath, processingPath, content };
|
|
111
|
-
}
|
|
112
|
-
/**
|
|
113
|
-
* Finalize a claimed inbox.
|
|
114
|
-
*
|
|
115
|
-
* - On success: delete processing file.
|
|
116
|
-
* - On failure: re-queue the claimed content back into inbox.md without
|
|
117
|
-
* overwriting any messages that arrived while processing.
|
|
118
|
-
*/
|
|
119
|
-
export function finalizeClaim(claim, success) {
|
|
120
|
-
if (success) {
|
|
121
|
-
try {
|
|
122
|
-
if (fs.existsSync(claim.processingPath)) {
|
|
123
|
-
fs.unlinkSync(claim.processingPath);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
catch {
|
|
127
|
-
// Best-effort cleanup
|
|
128
|
-
}
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
// Failure path: merge back into inbox.
|
|
132
|
-
try {
|
|
133
|
-
const claimedContent = fs.existsSync(claim.processingPath)
|
|
134
|
-
? fs.readFileSync(claim.processingPath, 'utf-8')
|
|
135
|
-
: claim.content;
|
|
136
|
-
if (!claimedContent.trim()) {
|
|
137
|
-
// Nothing to restore
|
|
138
|
-
if (fs.existsSync(claim.processingPath))
|
|
139
|
-
fs.unlinkSync(claim.processingPath);
|
|
140
|
-
return;
|
|
141
|
-
}
|
|
142
|
-
if (!fs.existsSync(claim.inboxPath)) {
|
|
143
|
-
fs.renameSync(claim.processingPath, claim.inboxPath);
|
|
144
|
-
return;
|
|
145
|
-
}
|
|
146
|
-
// Inbox exists (new messages arrived). Prepend claimed content so older messages come first.
|
|
147
|
-
const currentInbox = fs.readFileSync(claim.inboxPath, 'utf-8');
|
|
148
|
-
const merged = `${claimedContent.trimEnd()}\n\n${currentInbox.trimStart()}`;
|
|
149
|
-
const tmpPath = `${claim.inboxPath}.tmp`;
|
|
150
|
-
fs.writeFileSync(tmpPath, merged, 'utf-8');
|
|
151
|
-
fs.renameSync(tmpPath, claim.inboxPath);
|
|
152
|
-
if (fs.existsSync(claim.processingPath)) {
|
|
153
|
-
fs.unlinkSync(claim.processingPath);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
catch (err) {
|
|
157
|
-
// Last-resort: don't crash the supervisor on finalize
|
|
158
|
-
// eslint-disable-next-line no-console
|
|
159
|
-
console.error('[supervisor] Failed to finalize inbox claim:', err);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
//# sourceMappingURL=inbox.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"inbox.js","sourceRoot":"","sources":["../../src/supervisor/inbox.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAc7B,2BAA2B;AAC3B,oBAAoB;AACpB,sCAAsC;AACtC,YAAY;AACZ,EAAE;AACF,sCAAsC;AACtC,8BAA8B;AAC9B,qBAAqB;AACrB,YAAY;AACZ,MAAM,iBAAiB,GAAG,oCAAoC,CAAC;AAC/D,MAAM,qBAAqB,GAAG,2BAA2B,CAAC;AAC1D,MAAM,gBAAgB,GAAG,6BAA6B,CAAC;AAEvD;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAe;IAChD,MAAM,OAAO,GAAoG,EAAE,CAAC;IAEpH,IAAI,CAAyB,CAAC;IAC9B,0CAA0C;IAC1C,OAAO,CAAC,CAAC,GAAG,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACtD,OAAO,CAAC,IAAI,CAAC;YACX,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE;YACzB,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE;YAC9B,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM;YACtB,QAAQ,EAAE,KAAK;SAChB,CAAC,CAAC;IACL,CAAC;IAED,+CAA+C;IAC/C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,0CAA0C;QAC1C,OAAO,CAAC,CAAC,GAAG,qBAAqB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YAC1D,OAAO,CAAC,IAAI,CAAC;gBACX,KAAK,EAAE,CAAC,CAAC,KAAK;gBACd,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE;gBACzB,SAAS,EAAE,EAAE;gBACb,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM;gBACtB,QAAQ,EAAE,IAAI;aACf,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEpC,MAAM,QAAQ,GAAmB,EAAE,CAAC;IACpC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACxC,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QACvB,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAE5B,MAAM,SAAS,GAAG,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,SAAS,CAAC;QAC5C,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;QACnD,IAAI,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QAE5E,IAAI,SAAS,GAAG,GAAG,CAAC,SAAS,CAAC;QAC9B,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;YACjB,MAAM,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;YAC5C,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACX,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;gBACxB,qCAAqC;gBACrC,SAAS,GAAG,SAAS,CAAC,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;YAC5E,CAAC;QACH,CAAC;QAED,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC;QAE9B,IAAI,CAAC,GAAG,CAAC,IAAI;YAAE,SAAS;QACxB,IAAI,CAAC,SAAS;YAAE,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrD,IAAI,CAAC,IAAI;YAAE,SAAS;QAEpB,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACrD,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,SAAiB;IAC1C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO,IAAI,CAAC;IAE3C,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACpC,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,qBAAqB,CAAC,CAAC;IAE7D,IAAI,CAAC;QACH,EAAE,CAAC,UAAU,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;IAC3C,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,IAAI,GAAI,GAA6B,CAAC,IAAI,CAAC;QACjD,kEAAkE;QAClE,IAAI,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;YAC/D,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;IAED,IAAI,OAAO,GAAG,EAAE,CAAC;IACjB,IAAI,CAAC;QACH,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;IACrD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,EAAE,CAAC;IACf,CAAC;IAED,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,OAAO,EAAE,CAAC;AAChD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,KAAmB,EAAE,OAAgB;IACjE,IAAI,OAAO,EAAE,CAAC;QACZ,IAAI,CAAC;YACH,IAAI,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,cAAc,CAAC,EAAE,CAAC;gBACxC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;YACtC,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,sBAAsB;QACxB,CAAC;QACD,OAAO;IACT,CAAC;IAED,uCAAuC;IACvC,IAAI,CAAC;QACH,MAAM,cAAc,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,cAAc,CAAC;YACxD,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,cAAc,EAAE,OAAO,CAAC;YAChD,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;QAElB,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,EAAE,CAAC;YAC3B,qBAAqB;YACrB,IAAI,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,cAAc,CAAC;gBAAE,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;YAC7E,OAAO;QACT,CAAC;QAED,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;YACpC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;YACrD,OAAO;QACT,CAAC;QAED,6FAA6F;QAC7F,MAAM,YAAY,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAC/D,MAAM,MAAM,GAAG,GAAG,cAAc,CAAC,OAAO,EAAE,OAAO,YAAY,CAAC,SAAS,EAAE,EAAE,CAAC;QAE5E,MAAM,OAAO,GAAG,GAAG,KAAK,CAAC,SAAS,MAAM,CAAC;QACzC,EAAE,CAAC,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;QAC3C,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;QAExC,IAAI,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,cAAc,CAAC,EAAE,CAAC;YACxC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,sDAAsD;QACtD,sCAAsC;QACtC,OAAO,CAAC,KAAK,CAAC,8CAA8C,EAAE,GAAG,CAAC,CAAC;IACrE,CAAC;AACH,CAAC"}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Agent Relay Supervisor
|
|
3
|
-
*
|
|
4
|
-
* Exports for the spawn-per-message supervisor system.
|
|
5
|
-
*/
|
|
6
|
-
export * from './types.js';
|
|
7
|
-
export * from './state.js';
|
|
8
|
-
export * from './spawner.js';
|
|
9
|
-
export * from './supervisor.js';
|
|
10
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/supervisor/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC"}
|
package/dist/supervisor/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/supervisor/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC"}
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CLI Spawner
|
|
3
|
-
*
|
|
4
|
-
* Handles spawning fresh CLI instances for different agent types.
|
|
5
|
-
* Supports Claude Code, Codex, Cursor, and custom commands.
|
|
6
|
-
*/
|
|
7
|
-
import type { CLIType, SpawnResult, ParsedRelayCommand, SupervisorConfig } from './types.js';
|
|
8
|
-
/** Parsed structured markers from output */
|
|
9
|
-
export interface ParsedDecision {
|
|
10
|
-
what: string;
|
|
11
|
-
why: string;
|
|
12
|
-
}
|
|
13
|
-
export interface ParsedTodo {
|
|
14
|
-
task: string;
|
|
15
|
-
priority: 'high' | 'normal' | 'low';
|
|
16
|
-
owner?: string;
|
|
17
|
-
}
|
|
18
|
-
export interface ParsedDone {
|
|
19
|
-
taskMatch: string;
|
|
20
|
-
}
|
|
21
|
-
export interface ParsedStateMarkers {
|
|
22
|
-
decisions: ParsedDecision[];
|
|
23
|
-
todos: ParsedTodo[];
|
|
24
|
-
dones: ParsedDone[];
|
|
25
|
-
summary?: string;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Parse structured state markers from CLI output
|
|
29
|
-
*/
|
|
30
|
-
export declare function parseStateMarkers(output: string): ParsedStateMarkers;
|
|
31
|
-
/**
|
|
32
|
-
* Parse relay commands from CLI output
|
|
33
|
-
*/
|
|
34
|
-
export declare function parseRelayCommands(output: string): ParsedRelayCommand[];
|
|
35
|
-
/**
|
|
36
|
-
* CLI Spawner class
|
|
37
|
-
*/
|
|
38
|
-
export declare class CLISpawner {
|
|
39
|
-
private config;
|
|
40
|
-
constructor(config: SupervisorConfig);
|
|
41
|
-
/**
|
|
42
|
-
* Spawn a CLI with the given prompt
|
|
43
|
-
*/
|
|
44
|
-
spawn(cli: CLIType, prompt: string, cwd: string, customCommand?: string): Promise<SpawnResult>;
|
|
45
|
-
/**
|
|
46
|
-
* Parse a custom command string into cmd, args, promptFlag
|
|
47
|
-
*/
|
|
48
|
-
private parseCustomCommand;
|
|
49
|
-
/**
|
|
50
|
-
* Check if a CLI is available
|
|
51
|
-
*/
|
|
52
|
-
isAvailable(cli: CLIType, customCommand?: string): Promise<boolean>;
|
|
53
|
-
}
|
|
54
|
-
//# sourceMappingURL=spawner.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"spawner.d.ts","sourceRoot":"","sources":["../../src/supervisor/spawner.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AA0C7F,4CAA4C;AAC5C,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,kBAAkB,CA6DpE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,kBAAkB,EAAE,CA8BvE;AAED;;GAEG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAmB;gBAErB,MAAM,EAAE,gBAAgB;IAIpC;;OAEG;IACG,KAAK,CACT,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,WAAW,CAAC;IAmHvB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAwB1B;;OAEG;IACG,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAa1E"}
|