claude-mococo 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 +21 -0
- package/README.ko.md +171 -0
- package/README.md +180 -0
- package/defaults/shared-rules.md +70 -0
- package/dist/bot/client.d.ts +10 -0
- package/dist/bot/client.d.ts.map +1 -0
- package/dist/bot/client.js +886 -0
- package/dist/bot/client.js.map +1 -0
- package/dist/bot/discord-commands.d.ts +36 -0
- package/dist/bot/discord-commands.d.ts.map +1 -0
- package/dist/bot/discord-commands.js +811 -0
- package/dist/bot/discord-commands.js.map +1 -0
- package/dist/bot/embeds.d.ts +5 -0
- package/dist/bot/embeds.d.ts.map +1 -0
- package/dist/bot/embeds.js +20 -0
- package/dist/bot/embeds.js.map +1 -0
- package/dist/bot/episode-writer.d.ts +5 -0
- package/dist/bot/episode-writer.d.ts.map +1 -0
- package/dist/bot/episode-writer.js +131 -0
- package/dist/bot/episode-writer.js.map +1 -0
- package/dist/bot/improvement-scanner.d.ts +5 -0
- package/dist/bot/improvement-scanner.d.ts.map +1 -0
- package/dist/bot/improvement-scanner.js +563 -0
- package/dist/bot/improvement-scanner.js.map +1 -0
- package/dist/bot/inbox-compactor.d.ts +6 -0
- package/dist/bot/inbox-compactor.d.ts.map +1 -0
- package/dist/bot/inbox-compactor.js +550 -0
- package/dist/bot/inbox-compactor.js.map +1 -0
- package/dist/bot/memory-consolidator.d.ts +4 -0
- package/dist/bot/memory-consolidator.d.ts.map +1 -0
- package/dist/bot/memory-consolidator.js +258 -0
- package/dist/bot/memory-consolidator.js.map +1 -0
- package/dist/bot/router.d.ts +4 -0
- package/dist/bot/router.d.ts.map +1 -0
- package/dist/bot/router.js +24 -0
- package/dist/bot/router.js.map +1 -0
- package/dist/cli/commands/add.d.ts +2 -0
- package/dist/cli/commands/add.d.ts.map +1 -0
- package/dist/cli/commands/add.js +203 -0
- package/dist/cli/commands/add.js.map +1 -0
- package/dist/cli/commands/dev.d.ts +2 -0
- package/dist/cli/commands/dev.d.ts.map +1 -0
- package/dist/cli/commands/dev.js +44 -0
- package/dist/cli/commands/dev.js.map +1 -0
- package/dist/cli/commands/edit.d.ts +2 -0
- package/dist/cli/commands/edit.d.ts.map +1 -0
- package/dist/cli/commands/edit.js +213 -0
- package/dist/cli/commands/edit.js.map +1 -0
- package/dist/cli/commands/init.d.ts +2 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +126 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/list.d.ts +2 -0
- package/dist/cli/commands/list.d.ts.map +1 -0
- package/dist/cli/commands/list.js +21 -0
- package/dist/cli/commands/list.js.map +1 -0
- package/dist/cli/commands/remove.d.ts +2 -0
- package/dist/cli/commands/remove.d.ts.map +1 -0
- package/dist/cli/commands/remove.js +38 -0
- package/dist/cli/commands/remove.js.map +1 -0
- package/dist/cli/commands/restart.d.ts +2 -0
- package/dist/cli/commands/restart.d.ts.map +1 -0
- package/dist/cli/commands/restart.js +12 -0
- package/dist/cli/commands/restart.js.map +1 -0
- package/dist/cli/commands/start.d.ts +2 -0
- package/dist/cli/commands/start.d.ts.map +1 -0
- package/dist/cli/commands/start.js +33 -0
- package/dist/cli/commands/start.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +78 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/prompt-template.d.ts +18 -0
- package/dist/cli/prompt-template.d.ts.map +1 -0
- package/dist/cli/prompt-template.js +55 -0
- package/dist/cli/prompt-template.js.map +1 -0
- package/dist/cli/readline-utils.d.ts +5 -0
- package/dist/cli/readline-utils.d.ts.map +1 -0
- package/dist/cli/readline-utils.js +39 -0
- package/dist/cli/readline-utils.js.map +1 -0
- package/dist/cli/workspace.d.ts +7 -0
- package/dist/cli/workspace.d.ts.map +1 -0
- package/dist/cli/workspace.js +39 -0
- package/dist/cli/workspace.js.map +1 -0
- package/dist/config.d.ts +4 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +96 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/orchestrator/claude-engine.d.ts +8 -0
- package/dist/orchestrator/claude-engine.d.ts.map +1 -0
- package/dist/orchestrator/claude-engine.js +94 -0
- package/dist/orchestrator/claude-engine.js.map +1 -0
- package/dist/orchestrator/codex-engine.d.ts +10 -0
- package/dist/orchestrator/codex-engine.d.ts.map +1 -0
- package/dist/orchestrator/codex-engine.js +82 -0
- package/dist/orchestrator/codex-engine.js.map +1 -0
- package/dist/orchestrator/engine-base.d.ts +21 -0
- package/dist/orchestrator/engine-base.d.ts.map +1 -0
- package/dist/orchestrator/engine-base.js +20 -0
- package/dist/orchestrator/engine-base.js.map +1 -0
- package/dist/orchestrator/engines.d.ts +5 -0
- package/dist/orchestrator/engines.d.ts.map +1 -0
- package/dist/orchestrator/engines.js +16 -0
- package/dist/orchestrator/engines.js.map +1 -0
- package/dist/orchestrator/gemini-engine.d.ts +10 -0
- package/dist/orchestrator/gemini-engine.d.ts.map +1 -0
- package/dist/orchestrator/gemini-engine.js +79 -0
- package/dist/orchestrator/gemini-engine.js.map +1 -0
- package/dist/orchestrator/mcp-config.d.ts +4 -0
- package/dist/orchestrator/mcp-config.d.ts.map +1 -0
- package/dist/orchestrator/mcp-config.js +23 -0
- package/dist/orchestrator/mcp-config.js.map +1 -0
- package/dist/orchestrator/prompt-builder.d.ts +3 -0
- package/dist/orchestrator/prompt-builder.d.ts.map +1 -0
- package/dist/orchestrator/prompt-builder.js +445 -0
- package/dist/orchestrator/prompt-builder.js.map +1 -0
- package/dist/server/hook-receiver.d.ts +5 -0
- package/dist/server/hook-receiver.d.ts.map +1 -0
- package/dist/server/hook-receiver.js +52 -0
- package/dist/server/hook-receiver.js.map +1 -0
- package/dist/teams/concurrency.d.ts +12 -0
- package/dist/teams/concurrency.d.ts.map +1 -0
- package/dist/teams/concurrency.js +43 -0
- package/dist/teams/concurrency.js.map +1 -0
- package/dist/teams/context.d.ts +5 -0
- package/dist/teams/context.d.ts.map +1 -0
- package/dist/teams/context.js +33 -0
- package/dist/teams/context.js.map +1 -0
- package/dist/teams/dispatch-ledger.d.ts +27 -0
- package/dist/teams/dispatch-ledger.d.ts.map +1 -0
- package/dist/teams/dispatch-ledger.js +90 -0
- package/dist/teams/dispatch-ledger.js.map +1 -0
- package/dist/teams/invoker.d.ts +9 -0
- package/dist/teams/invoker.d.ts.map +1 -0
- package/dist/teams/invoker.js +54 -0
- package/dist/teams/invoker.js.map +1 -0
- package/dist/types.d.ts +110 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/fs.d.ts +3 -0
- package/dist/utils/fs.d.ts.map +1 -0
- package/dist/utils/fs.js +17 -0
- package/dist/utils/fs.js.map +1 -0
- package/dist/utils/github-status.d.ts +25 -0
- package/dist/utils/github-status.d.ts.map +1 -0
- package/dist/utils/github-status.js +158 -0
- package/dist/utils/github-status.js.map +1 -0
- package/dist/utils/haiku.d.ts +6 -0
- package/dist/utils/haiku.d.ts.map +1 -0
- package/dist/utils/haiku.js +43 -0
- package/dist/utils/haiku.js.map +1 -0
- package/hooks/event-bridge.sh +21 -0
- package/hooks/permission-gate.sh +67 -0
- package/package.json +52 -0
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import http from 'node:http';
|
|
2
|
+
import { EventEmitter } from 'node:events';
|
|
3
|
+
export declare const hookEvents: EventEmitter<[never]>;
|
|
4
|
+
export declare function startHookServer(port: number): http.Server<typeof http.IncomingMessage, typeof http.ServerResponse>;
|
|
5
|
+
//# sourceMappingURL=hook-receiver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hook-receiver.d.ts","sourceRoot":"","sources":["../../src/server/hook-receiver.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,eAAO,MAAM,UAAU,uBAAqB,CAAC;AAI7C,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,wEAiD3C"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import http from 'node:http';
|
|
2
|
+
import { EventEmitter } from 'node:events';
|
|
3
|
+
export const hookEvents = new EventEmitter();
|
|
4
|
+
const MAX_BODY_SIZE = 1024 * 1024; // 1MB limit
|
|
5
|
+
export function startHookServer(port) {
|
|
6
|
+
const server = http.createServer((req, res) => {
|
|
7
|
+
if (req.method !== 'POST' || req.url !== '/hook') {
|
|
8
|
+
res.writeHead(404);
|
|
9
|
+
res.end();
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
let body = '';
|
|
13
|
+
let size = 0;
|
|
14
|
+
let aborted = false;
|
|
15
|
+
req.on('data', (chunk) => {
|
|
16
|
+
size += chunk.length;
|
|
17
|
+
if (size > MAX_BODY_SIZE) {
|
|
18
|
+
if (!aborted) {
|
|
19
|
+
aborted = true;
|
|
20
|
+
console.warn(`[hook-receiver] Request body exceeded ${MAX_BODY_SIZE} bytes, rejecting`);
|
|
21
|
+
res.writeHead(413);
|
|
22
|
+
res.end();
|
|
23
|
+
req.destroy();
|
|
24
|
+
}
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
body += chunk;
|
|
28
|
+
});
|
|
29
|
+
req.on('end', () => {
|
|
30
|
+
if (aborted)
|
|
31
|
+
return;
|
|
32
|
+
try {
|
|
33
|
+
const event = JSON.parse(body);
|
|
34
|
+
hookEvents.emit('any', event);
|
|
35
|
+
hookEvents.emit(event.hook_event_name, event);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
// invalid JSON, ignore
|
|
39
|
+
}
|
|
40
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
41
|
+
res.end('{"ok":true}');
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
server.on('error', (err) => {
|
|
45
|
+
console.error(`[hook-receiver] Server error:`, err);
|
|
46
|
+
});
|
|
47
|
+
server.listen(port, () => {
|
|
48
|
+
console.log(`Hook receiver listening on :${port}`);
|
|
49
|
+
});
|
|
50
|
+
return server;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=hook-receiver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hook-receiver.js","sourceRoot":"","sources":["../../src/server/hook-receiver.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,YAAY,EAAE,CAAC;AAE7C,MAAM,aAAa,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,YAAY;AAE/C,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QAC5C,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,IAAI,GAAG,CAAC,GAAG,KAAK,OAAO,EAAE,CAAC;YACjD,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YACnB,GAAG,CAAC,GAAG,EAAE,CAAC;YACV,OAAO;QACT,CAAC;QAED,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,IAAI,IAAI,GAAG,CAAC,CAAC;QACb,IAAI,OAAO,GAAG,KAAK,CAAC;QAEpB,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;YACvB,IAAI,IAAI,KAAK,CAAC,MAAM,CAAC;YACrB,IAAI,IAAI,GAAG,aAAa,EAAE,CAAC;gBACzB,IAAI,CAAC,OAAO,EAAE,CAAC;oBACb,OAAO,GAAG,IAAI,CAAC;oBACf,OAAO,CAAC,IAAI,CAAC,yCAAyC,aAAa,mBAAmB,CAAC,CAAC;oBACxF,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;oBACnB,GAAG,CAAC,GAAG,EAAE,CAAC;oBACV,GAAG,CAAC,OAAO,EAAE,CAAC;gBAChB,CAAC;gBACD,OAAO;YACT,CAAC;YACD,IAAI,IAAI,KAAK,CAAC;QAChB,CAAC,CAAC,CAAC;QACH,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;YACjB,IAAI,OAAO;gBAAE,OAAO;YACpB,IAAI,CAAC;gBACH,MAAM,KAAK,GAAc,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC1C,UAAU,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;gBAC9B,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC;YAChD,CAAC;YAAC,MAAM,CAAC;gBACP,uBAAuB;YACzB,CAAC;YACD,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;YAC3D,GAAG,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;QACzB,OAAO,CAAC,KAAK,CAAC,+BAA+B,EAAE,GAAG,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE;QACvB,OAAO,CAAC,GAAG,CAAC,+BAA+B,IAAI,EAAE,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { TeamId } from '../types.js';
|
|
2
|
+
export declare function isBusy(teamId: TeamId): boolean;
|
|
3
|
+
export declare function markBusy(teamId: TeamId, task: string): void;
|
|
4
|
+
export declare function markFree(teamId: TeamId): void;
|
|
5
|
+
export declare function waitForFree(teamId: TeamId): Promise<void>;
|
|
6
|
+
export declare function isQueued(teamId: TeamId): boolean;
|
|
7
|
+
export declare function getStatus(): Record<string, {
|
|
8
|
+
busy: boolean;
|
|
9
|
+
since?: Date;
|
|
10
|
+
task?: string;
|
|
11
|
+
}>;
|
|
12
|
+
//# sourceMappingURL=concurrency.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"concurrency.d.ts","sourceRoot":"","sources":["../../src/teams/concurrency.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAK1C,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE9C;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,QAEpD;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,QAOtC;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAYzD;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAGhD;AAED,wBAAgB,SAAS,IAAI,MAAM,CAAC,MAAM,EAAE;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,IAAI,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAM1F"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
const busyTeams = new Map();
|
|
2
|
+
const queues = new Map();
|
|
3
|
+
export function isBusy(teamId) {
|
|
4
|
+
return busyTeams.has(teamId);
|
|
5
|
+
}
|
|
6
|
+
export function markBusy(teamId, task) {
|
|
7
|
+
busyTeams.set(teamId, { since: new Date(), task });
|
|
8
|
+
}
|
|
9
|
+
export function markFree(teamId) {
|
|
10
|
+
busyTeams.delete(teamId);
|
|
11
|
+
const queue = queues.get(teamId);
|
|
12
|
+
if (queue && queue.length > 0) {
|
|
13
|
+
const next = queue.shift();
|
|
14
|
+
next();
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export function waitForFree(teamId) {
|
|
18
|
+
if (!isBusy(teamId))
|
|
19
|
+
return Promise.resolve();
|
|
20
|
+
return new Promise((resolve) => {
|
|
21
|
+
// Re-check after Promise creation — markFree() may have run between
|
|
22
|
+
// the initial check and this point
|
|
23
|
+
if (!isBusy(teamId)) {
|
|
24
|
+
resolve();
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (!queues.has(teamId))
|
|
28
|
+
queues.set(teamId, []);
|
|
29
|
+
queues.get(teamId).push(resolve);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
export function isQueued(teamId) {
|
|
33
|
+
const queue = queues.get(teamId);
|
|
34
|
+
return !!queue && queue.length > 0;
|
|
35
|
+
}
|
|
36
|
+
export function getStatus() {
|
|
37
|
+
const status = {};
|
|
38
|
+
for (const [id, info] of busyTeams) {
|
|
39
|
+
status[id] = { busy: true, ...info };
|
|
40
|
+
}
|
|
41
|
+
return status;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=concurrency.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"concurrency.js","sourceRoot":"","sources":["../../src/teams/concurrency.ts"],"names":[],"mappings":"AAEA,MAAM,SAAS,GAAG,IAAI,GAAG,EAAyC,CAAC;AACnE,MAAM,MAAM,GAAG,IAAI,GAAG,EAA0B,CAAC;AAEjD,MAAM,UAAU,MAAM,CAAC,MAAc;IACnC,OAAO,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,MAAc,EAAE,IAAY;IACnD,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,IAAI,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;AACrD,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,MAAc;IACrC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACzB,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACjC,IAAI,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,EAAG,CAAC;QAC5B,IAAI,EAAE,CAAC;IACT,CAAC;AACH,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,MAAc;IACxC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;QAAE,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC9C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,oEAAoE;QACpE,mCAAmC;QACnC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;YACpB,OAAO,EAAE,CAAC;YACV,OAAO;QACT,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC;YAAE,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAChD,MAAM,CAAC,GAAG,CAAC,MAAM,CAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,MAAc;IACrC,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACjC,OAAO,CAAC,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,MAAM,MAAM,GAAmE,EAAE,CAAC;IAClF,KAAK,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,SAAS,EAAE,CAAC;QACnC,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,CAAC;IACvC,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ConversationMessage } from '../types.js';
|
|
2
|
+
export declare function addMessage(channelId: string, msg: ConversationMessage): void;
|
|
3
|
+
export declare function getRecentConversation(channelId: string, windowSize: number): ConversationMessage[];
|
|
4
|
+
export declare function formatConversation(messages: ConversationMessage[]): string;
|
|
5
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/teams/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAMvD,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,mBAAmB,QAiBrE;AAED,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,mBAAmB,EAAE,CAGvB;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,mBAAmB,EAAE,GAAG,MAAM,CAM1E"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// In-memory conversation history (per channel)
|
|
2
|
+
const conversations = new Map();
|
|
3
|
+
const MAX_CHANNELS = 100;
|
|
4
|
+
export function addMessage(channelId, msg) {
|
|
5
|
+
// LRU: delete-and-re-set to move channel to end of Map insertion order
|
|
6
|
+
const existing = conversations.get(channelId);
|
|
7
|
+
if (existing)
|
|
8
|
+
conversations.delete(channelId);
|
|
9
|
+
const history = existing ?? [];
|
|
10
|
+
history.push(msg);
|
|
11
|
+
// Keep last 100 messages in memory
|
|
12
|
+
if (history.length > 100)
|
|
13
|
+
history.splice(0, history.length - 100);
|
|
14
|
+
conversations.set(channelId, history);
|
|
15
|
+
// Evict oldest channel entry when exceeding limit
|
|
16
|
+
if (conversations.size > MAX_CHANNELS) {
|
|
17
|
+
const oldestKey = conversations.keys().next().value;
|
|
18
|
+
if (oldestKey)
|
|
19
|
+
conversations.delete(oldestKey);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export function getRecentConversation(channelId, windowSize) {
|
|
23
|
+
const history = conversations.get(channelId) ?? [];
|
|
24
|
+
return history.slice(-windowSize);
|
|
25
|
+
}
|
|
26
|
+
export function formatConversation(messages) {
|
|
27
|
+
return messages.map(m => {
|
|
28
|
+
const sender = m.teamId === 'human' ? 'Human' : m.teamName;
|
|
29
|
+
const time = m.timestamp.toISOString().slice(11, 19);
|
|
30
|
+
return `[${time}] ${sender}: ${m.content}`;
|
|
31
|
+
}).join('\n');
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/teams/context.ts"],"names":[],"mappings":"AAEA,+CAA+C;AAC/C,MAAM,aAAa,GAAG,IAAI,GAAG,EAAiC,CAAC;AAC/D,MAAM,YAAY,GAAG,GAAG,CAAC;AAEzB,MAAM,UAAU,UAAU,CAAC,SAAiB,EAAE,GAAwB;IACpE,uEAAuE;IACvE,MAAM,QAAQ,GAAG,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAC9C,IAAI,QAAQ;QAAE,aAAa,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAE9C,MAAM,OAAO,GAAG,QAAQ,IAAI,EAAE,CAAC;IAC/B,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAClB,mCAAmC;IACnC,IAAI,OAAO,CAAC,MAAM,GAAG,GAAG;QAAE,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC;IAElE,aAAa,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IAEtC,kDAAkD;IAClD,IAAI,aAAa,CAAC,IAAI,GAAG,YAAY,EAAE,CAAC;QACtC,MAAM,SAAS,GAAG,aAAa,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;QACpD,IAAI,SAAS;YAAE,aAAa,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACjD,CAAC;AACH,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,SAAiB,EACjB,UAAkB;IAElB,MAAM,OAAO,GAAG,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;IACnD,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,QAA+B;IAChE,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;QACtB,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;QAC3D,MAAM,IAAI,GAAG,CAAC,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QACrD,OAAO,IAAI,IAAI,KAAK,MAAM,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC;IAC7C,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { DispatchRecord } from '../types.js';
|
|
2
|
+
declare class DispatchLedger {
|
|
3
|
+
private records;
|
|
4
|
+
private hardCutoffMs;
|
|
5
|
+
/** Override default hard cutoff (e.g., based on team maxBudget). */
|
|
6
|
+
setHardCutoffMs(ms: number): void;
|
|
7
|
+
record(chainId: string, fromTeam: string, toTeam: string, channelId: string, reason: string, hardCutoffMs?: number): DispatchRecord;
|
|
8
|
+
/**
|
|
9
|
+
* Mark records resolved when toTeam's output mentions fromTeam.
|
|
10
|
+
* For system-dispatched records (fromTeam='system'), any response from toTeam
|
|
11
|
+
* auto-resolves since teams cannot mention 'system'.
|
|
12
|
+
*/
|
|
13
|
+
resolve(toTeam: string, mentionedTeamIds: string[]): void;
|
|
14
|
+
/** Resolve a specific record by ID (for system auto-resolution). */
|
|
15
|
+
resolveById(recordId: string): void;
|
|
16
|
+
/**
|
|
17
|
+
* Get unresolved dispatches, optionally filtered by age.
|
|
18
|
+
*/
|
|
19
|
+
getUnresolved(olderThanMs?: number): DispatchRecord[];
|
|
20
|
+
/**
|
|
21
|
+
* Remove expired records to prevent memory growth.
|
|
22
|
+
*/
|
|
23
|
+
private cleanup;
|
|
24
|
+
}
|
|
25
|
+
export declare const ledger: DispatchLedger;
|
|
26
|
+
export {};
|
|
27
|
+
//# sourceMappingURL=dispatch-ledger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatch-ledger.d.ts","sourceRoot":"","sources":["../../src/teams/dispatch-ledger.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAQlD,cAAM,cAAc;IAClB,OAAO,CAAC,OAAO,CAAsD;IACrE,OAAO,CAAC,YAAY,CAA0B;IAE9C,oEAAoE;IACpE,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAIjC,MAAM,CACJ,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,YAAY,CAAC,EAAE,MAAM,GACpB,cAAc;IAiBjB;;;;OAIG;IACH,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,GAAG,IAAI;IAWzD,oEAAoE;IACpE,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAQnC;;OAEG;IACH,aAAa,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,cAAc,EAAE;IASrD;;OAEG;IACH,OAAO,CAAC,OAAO;CAkBhB;AAGD,eAAO,MAAM,MAAM,gBAAuB,CAAC"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import crypto from 'node:crypto';
|
|
2
|
+
const MAX_RECORDS = 200;
|
|
3
|
+
/** 해결된 레코드 만료 시간 (기본 1시간) */
|
|
4
|
+
const EXPIRE_MS = 60 * 60 * 1000; // 1 hour
|
|
5
|
+
/** 미해결 레코드 강제 만료 시간 기본값 (6시간) */
|
|
6
|
+
const DEFAULT_HARD_CUTOFF_MS = 6 * 60 * 60 * 1000; // 6 hours
|
|
7
|
+
class DispatchLedger {
|
|
8
|
+
records = [];
|
|
9
|
+
hardCutoffMs = DEFAULT_HARD_CUTOFF_MS;
|
|
10
|
+
/** Override default hard cutoff (e.g., based on team maxBudget). */
|
|
11
|
+
setHardCutoffMs(ms) {
|
|
12
|
+
this.hardCutoffMs = ms;
|
|
13
|
+
}
|
|
14
|
+
record(chainId, fromTeam, toTeam, channelId, reason, hardCutoffMs) {
|
|
15
|
+
const rec = {
|
|
16
|
+
id: crypto.randomUUID(),
|
|
17
|
+
chainId,
|
|
18
|
+
fromTeam,
|
|
19
|
+
toTeam,
|
|
20
|
+
channelId,
|
|
21
|
+
reason: reason.slice(0, 200),
|
|
22
|
+
dispatchedAt: Date.now(),
|
|
23
|
+
resolved: false,
|
|
24
|
+
hardCutoffMs,
|
|
25
|
+
};
|
|
26
|
+
this.records.push(rec);
|
|
27
|
+
this.cleanup();
|
|
28
|
+
return rec;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Mark records resolved when toTeam's output mentions fromTeam.
|
|
32
|
+
* For system-dispatched records (fromTeam='system'), any response from toTeam
|
|
33
|
+
* auto-resolves since teams cannot mention 'system'.
|
|
34
|
+
*/
|
|
35
|
+
resolve(toTeam, mentionedTeamIds) {
|
|
36
|
+
for (const rec of this.records) {
|
|
37
|
+
if (rec.toTeam === toTeam && !rec.resolved) {
|
|
38
|
+
if (rec.fromTeam === 'system' || mentionedTeamIds.includes(rec.fromTeam)) {
|
|
39
|
+
rec.resolved = true;
|
|
40
|
+
rec.resolvedAt = Date.now();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/** Resolve a specific record by ID (for system auto-resolution). */
|
|
46
|
+
resolveById(recordId) {
|
|
47
|
+
const rec = this.records.find(r => r.id === recordId);
|
|
48
|
+
if (rec && !rec.resolved) {
|
|
49
|
+
rec.resolved = true;
|
|
50
|
+
rec.resolvedAt = Date.now();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Get unresolved dispatches, optionally filtered by age.
|
|
55
|
+
*/
|
|
56
|
+
getUnresolved(olderThanMs) {
|
|
57
|
+
const now = Date.now();
|
|
58
|
+
return this.records.filter(r => {
|
|
59
|
+
if (r.resolved)
|
|
60
|
+
return false;
|
|
61
|
+
if (olderThanMs && (now - r.dispatchedAt) < olderThanMs)
|
|
62
|
+
return false;
|
|
63
|
+
return true;
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Remove expired records to prevent memory growth.
|
|
68
|
+
*/
|
|
69
|
+
cleanup() {
|
|
70
|
+
const now = Date.now();
|
|
71
|
+
const cutoff = now - EXPIRE_MS;
|
|
72
|
+
this.records = this.records
|
|
73
|
+
.filter(r => {
|
|
74
|
+
const recCutoff = now - (r.hardCutoffMs ?? this.hardCutoffMs);
|
|
75
|
+
if (r.dispatchedAt < recCutoff) {
|
|
76
|
+
if (!r.resolved) {
|
|
77
|
+
const elapsedMin = Math.round((now - r.dispatchedAt) / 60_000);
|
|
78
|
+
const cutoffMin = Math.round((r.hardCutoffMs ?? this.hardCutoffMs) / 60_000);
|
|
79
|
+
console.warn(`[dispatch-ledger] Force-expiring unresolved record: ${r.fromTeam}→${r.toTeam} (${r.reason.slice(0, 50)}) — ${elapsedMin}분 경과 (timeout: ${cutoffMin}분)`);
|
|
80
|
+
}
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
return r.dispatchedAt > cutoff || !r.resolved;
|
|
84
|
+
})
|
|
85
|
+
.slice(-MAX_RECORDS);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// Singleton
|
|
89
|
+
export const ledger = new DispatchLedger();
|
|
90
|
+
//# sourceMappingURL=dispatch-ledger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatch-ledger.js","sourceRoot":"","sources":["../../src/teams/dispatch-ledger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { TeamConfig, TeamsConfig, TeamInvocation } from '../types.js';
|
|
2
|
+
export interface InvocationResult {
|
|
3
|
+
teamId: string;
|
|
4
|
+
output: string;
|
|
5
|
+
cost: number;
|
|
6
|
+
timedOut?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare function invokeTeam(team: TeamConfig, invocation: TeamInvocation, config: TeamsConfig, preloadedInbox?: string): Promise<InvocationResult>;
|
|
9
|
+
//# sourceMappingURL=invoker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invoker.d.ts","sourceRoot":"","sources":["../../src/teams/invoker.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAI3E,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,wBAAsB,UAAU,CAC9B,IAAI,EAAE,UAAU,EAChB,UAAU,EAAE,cAAc,EAC1B,MAAM,EAAE,WAAW,EACnB,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,gBAAgB,CAAC,CAyD3B"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { createEngine } from '../orchestrator/engines.js';
|
|
2
|
+
import { buildTeamPrompt } from '../orchestrator/prompt-builder.js';
|
|
3
|
+
const INVOKE_TIMEOUT_MS = 10 * 60 * 1000; // 10 minutes — safety net above engine-level timeout
|
|
4
|
+
export async function invokeTeam(team, invocation, config, preloadedInbox) {
|
|
5
|
+
const prompt = await buildTeamPrompt(team, invocation, config, preloadedInbox);
|
|
6
|
+
const engine = createEngine(team.engine, {
|
|
7
|
+
prompt,
|
|
8
|
+
cwd: config.workspacePath,
|
|
9
|
+
model: team.model,
|
|
10
|
+
maxBudget: team.maxBudget,
|
|
11
|
+
teamId: team.id,
|
|
12
|
+
gitName: team.git.name,
|
|
13
|
+
gitEmail: team.git.email,
|
|
14
|
+
mcpServers: team.mcpServers,
|
|
15
|
+
});
|
|
16
|
+
// Track last known cost from engine messages so timeout can report actual spend
|
|
17
|
+
let lastKnownCost = 0;
|
|
18
|
+
engine.on('message', (event) => {
|
|
19
|
+
if (typeof event.total_cost_usd === 'number') {
|
|
20
|
+
lastKnownCost = event.total_cost_usd;
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
const enginePromise = new Promise((resolve, reject) => {
|
|
24
|
+
let resolved = false;
|
|
25
|
+
engine.on('result', (event) => {
|
|
26
|
+
resolved = true;
|
|
27
|
+
resolve({
|
|
28
|
+
teamId: team.id,
|
|
29
|
+
output: event.result ?? '',
|
|
30
|
+
cost: event.total_cost_usd ?? 0,
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
engine.on('exit', (code) => {
|
|
34
|
+
if (!resolved) {
|
|
35
|
+
reject(new Error(`Team ${team.id} (${team.engine}) exited with code ${code}`));
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
engine.start().catch(reject);
|
|
39
|
+
});
|
|
40
|
+
const timeoutPromise = new Promise((resolve) => {
|
|
41
|
+
setTimeout(() => {
|
|
42
|
+
engine.kill();
|
|
43
|
+
console.warn(`[${team.id}] Timed out after ${INVOKE_TIMEOUT_MS / 1000}s (cost so far: $${lastKnownCost.toFixed(4)}) — returning partial result for continuation`);
|
|
44
|
+
resolve({
|
|
45
|
+
teamId: team.id,
|
|
46
|
+
output: '',
|
|
47
|
+
cost: lastKnownCost,
|
|
48
|
+
timedOut: true,
|
|
49
|
+
});
|
|
50
|
+
}, INVOKE_TIMEOUT_MS);
|
|
51
|
+
});
|
|
52
|
+
return Promise.race([enginePromise, timeoutPromise]);
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=invoker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invoker.js","sourceRoot":"","sources":["../../src/teams/invoker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAGpE,MAAM,iBAAiB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,qDAAqD;AAS/F,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,IAAgB,EAChB,UAA0B,EAC1B,MAAmB,EACnB,cAAuB;IAEvB,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,cAAc,CAAC,CAAC;IAE/E,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,MAAM,EAAE;QACvC,MAAM;QACN,GAAG,EAAE,MAAM,CAAC,aAAa;QACzB,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,MAAM,EAAE,IAAI,CAAC,EAAE;QACf,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI;QACtB,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK;QACxB,UAAU,EAAE,IAAI,CAAC,UAAU;KAC5B,CAAC,CAAC;IAEH,gFAAgF;IAChF,IAAI,aAAa,GAAG,CAAC,CAAC;IACtB,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE;QAC7B,IAAI,OAAO,KAAK,CAAC,cAAc,KAAK,QAAQ,EAAE,CAAC;YAC7C,aAAa,GAAG,KAAK,CAAC,cAAc,CAAC;QACvC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,aAAa,GAAG,IAAI,OAAO,CAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACtE,IAAI,QAAQ,GAAG,KAAK,CAAC;QAErB,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE;YAC5B,QAAQ,GAAG,IAAI,CAAC;YAChB,OAAO,CAAC;gBACN,MAAM,EAAE,IAAI,CAAC,EAAE;gBACf,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,EAAE;gBAC1B,IAAI,EAAE,KAAK,CAAC,cAAc,IAAI,CAAC;aAChC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;YACzB,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,MAAM,CAAC,IAAI,KAAK,CAAC,QAAQ,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,MAAM,sBAAsB,IAAI,EAAE,CAAC,CAAC,CAAC;YACjF,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,MAAM,cAAc,GAAG,IAAI,OAAO,CAAmB,CAAC,OAAO,EAAE,EAAE;QAC/D,UAAU,CAAC,GAAG,EAAE;YACd,MAAM,CAAC,IAAI,EAAE,CAAC;YACd,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,EAAE,qBAAqB,iBAAiB,GAAG,IAAI,oBAAoB,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,+CAA+C,CAAC,CAAC;YAClK,OAAO,CAAC;gBACN,MAAM,EAAE,IAAI,CAAC,EAAE;gBACf,MAAM,EAAE,EAAE;gBACV,IAAI,EAAE,aAAa;gBACnB,QAAQ,EAAE,IAAI;aACf,CAAC,CAAC;QACL,CAAC,EAAE,iBAAiB,CAAC,CAAC;IACxB,CAAC,CAAC,CAAC;IAEH,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,aAAa,EAAE,cAAc,CAAC,CAAC,CAAC;AACvD,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
export type TeamId = string;
|
|
2
|
+
export type Engine = 'claude' | 'codex' | 'gemini';
|
|
3
|
+
export interface McpServerConfig {
|
|
4
|
+
command: string;
|
|
5
|
+
args?: string[];
|
|
6
|
+
env?: Record<string, string>;
|
|
7
|
+
}
|
|
8
|
+
export interface GitIdentity {
|
|
9
|
+
name: string;
|
|
10
|
+
email: string;
|
|
11
|
+
}
|
|
12
|
+
export interface TeamConfig {
|
|
13
|
+
id: TeamId;
|
|
14
|
+
name: string;
|
|
15
|
+
color: number;
|
|
16
|
+
avatar: string;
|
|
17
|
+
engine: Engine;
|
|
18
|
+
model: string;
|
|
19
|
+
maxBudget: number;
|
|
20
|
+
prompt: string;
|
|
21
|
+
isLeader?: boolean;
|
|
22
|
+
channels?: string[];
|
|
23
|
+
discordUserId?: string;
|
|
24
|
+
useTeams?: boolean;
|
|
25
|
+
teamRules?: string[];
|
|
26
|
+
git: GitIdentity;
|
|
27
|
+
discordToken: string;
|
|
28
|
+
mcpServers?: Record<string, McpServerConfig>;
|
|
29
|
+
permissions: {
|
|
30
|
+
allow?: string[];
|
|
31
|
+
deny?: string[];
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export interface TeamsConfig {
|
|
35
|
+
teams: Record<string, TeamConfig>;
|
|
36
|
+
globalDeny: string[];
|
|
37
|
+
conversationWindow: number;
|
|
38
|
+
workspacePath: string;
|
|
39
|
+
humanDiscordId?: string;
|
|
40
|
+
humanTitle?: string;
|
|
41
|
+
}
|
|
42
|
+
export interface ConversationMessage {
|
|
43
|
+
teamId: string | 'human';
|
|
44
|
+
teamName: string;
|
|
45
|
+
discordId?: string;
|
|
46
|
+
content: string;
|
|
47
|
+
timestamp: Date;
|
|
48
|
+
mentions: string[];
|
|
49
|
+
}
|
|
50
|
+
export interface TeamInvocation {
|
|
51
|
+
teamId: string;
|
|
52
|
+
trigger: 'human_message' | 'team_mention' | 'direct_command';
|
|
53
|
+
message: ConversationMessage;
|
|
54
|
+
conversation: ConversationMessage[];
|
|
55
|
+
channelId: string;
|
|
56
|
+
}
|
|
57
|
+
export interface Episode {
|
|
58
|
+
ts: number;
|
|
59
|
+
teamId: string;
|
|
60
|
+
channelId: string;
|
|
61
|
+
trigger: 'human_message' | 'team_mention' | 'system';
|
|
62
|
+
summary: string;
|
|
63
|
+
mentions: string[];
|
|
64
|
+
}
|
|
65
|
+
export interface EnvConfig {
|
|
66
|
+
workChannelId?: string;
|
|
67
|
+
hookPort: number;
|
|
68
|
+
memberTrackingChannelId?: string;
|
|
69
|
+
decisionLogChannelId?: string;
|
|
70
|
+
}
|
|
71
|
+
export interface ChainContext {
|
|
72
|
+
chainId: string;
|
|
73
|
+
totalInvocations: number;
|
|
74
|
+
maxBudget: number;
|
|
75
|
+
recentPath: string[];
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Tracks work dispatched between teams for follow-up.
|
|
79
|
+
*
|
|
80
|
+
* Invariants:
|
|
81
|
+
* - `resolvedAt` is meaningful only when `resolved === true`.
|
|
82
|
+
* When `resolved` is `false`, `resolvedAt` is always `undefined`.
|
|
83
|
+
* - Once `resolved` is set to `true`, it is never reverted to `false`.
|
|
84
|
+
*/
|
|
85
|
+
export interface DispatchRecord {
|
|
86
|
+
id: string;
|
|
87
|
+
chainId: string;
|
|
88
|
+
fromTeam: string;
|
|
89
|
+
toTeam: string;
|
|
90
|
+
channelId: string;
|
|
91
|
+
reason: string;
|
|
92
|
+
dispatchedAt: number;
|
|
93
|
+
/**
|
|
94
|
+
* Timestamp (ms) when this record was resolved.
|
|
95
|
+
* Only meaningful when `resolved === true`; always `undefined` otherwise.
|
|
96
|
+
*/
|
|
97
|
+
resolvedAt?: number;
|
|
98
|
+
resolved: boolean;
|
|
99
|
+
}
|
|
100
|
+
export interface HookEvent {
|
|
101
|
+
hook_event_name: string;
|
|
102
|
+
session_id: string;
|
|
103
|
+
mococo_team?: string;
|
|
104
|
+
teammate_name?: string;
|
|
105
|
+
task_subject?: string;
|
|
106
|
+
tool_name?: string;
|
|
107
|
+
tool_input?: Record<string, unknown>;
|
|
108
|
+
[key: string]: unknown;
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../../src/utils/fs.ts"],"names":[],"mappings":"AAEA,iFAAiF;AACjF,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CASvE"}
|
package/dist/utils/fs.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
/** Atomic write: write to temp file then rename to avoid corruption on crash. */
|
|
3
|
+
export function atomicWriteSync(filePath, content) {
|
|
4
|
+
const tmp = filePath + '.tmp';
|
|
5
|
+
try {
|
|
6
|
+
fs.writeFileSync(tmp, content);
|
|
7
|
+
fs.renameSync(tmp, filePath);
|
|
8
|
+
}
|
|
9
|
+
catch (err) {
|
|
10
|
+
try {
|
|
11
|
+
fs.unlinkSync(tmp);
|
|
12
|
+
}
|
|
13
|
+
catch { }
|
|
14
|
+
throw err;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=fs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fs.js","sourceRoot":"","sources":["../../src/utils/fs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB,iFAAiF;AACjF,MAAM,UAAU,eAAe,CAAC,QAAgB,EAAE,OAAe;IAC/D,MAAM,GAAG,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC9B,IAAI,CAAC;QACH,EAAE,CAAC,aAAa,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAC/B,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IAC/B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC;YAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;QACpC,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface PRInfo {
|
|
2
|
+
owner: string;
|
|
3
|
+
repo: string;
|
|
4
|
+
number: number;
|
|
5
|
+
}
|
|
6
|
+
export interface PRStatus extends PRInfo {
|
|
7
|
+
state: 'open' | 'closed';
|
|
8
|
+
merged: boolean;
|
|
9
|
+
title: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function discoverRepos(workspacePath: string): Map<string, {
|
|
12
|
+
owner: string;
|
|
13
|
+
repo: string;
|
|
14
|
+
}>;
|
|
15
|
+
export declare function extractPRs(content: string, repos: Map<string, {
|
|
16
|
+
owner: string;
|
|
17
|
+
repo: string;
|
|
18
|
+
}>): PRInfo[];
|
|
19
|
+
export declare function checkPRStatuses(prs: PRInfo[]): Promise<PRStatus[]>;
|
|
20
|
+
export declare function formatPRStatusReport(statuses: PRStatus[]): string;
|
|
21
|
+
export declare function verifyPRStatuses(workspacePath: string, teamIds: string[]): Promise<{
|
|
22
|
+
statuses: PRStatus[];
|
|
23
|
+
report: string;
|
|
24
|
+
}>;
|
|
25
|
+
//# sourceMappingURL=github-status.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github-status.d.ts","sourceRoot":"","sources":["../../src/utils/github-status.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,MAAM;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,QAAS,SAAQ,MAAM;IACtC,KAAK,EAAE,MAAM,GAAG,QAAQ,CAAC;IACzB,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAMD,wBAAgB,aAAa,CAAC,aAAa,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAuBjG;AAMD,wBAAgB,UAAU,CACxB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,GAClD,MAAM,EAAE,CAgCV;AAMD,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CA4CxE;AAMD,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,MAAM,CAajE;AAMD,wBAAsB,gBAAgB,CAAC,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IACxF,QAAQ,EAAE,QAAQ,EAAE,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC,CAsCD"}
|