@excitedjs/dreamux 0.1.4 → 0.3.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/README.md +170 -154
- package/bin/tm +30 -0
- package/dist/admin/client.js +98 -0
- package/dist/admin/client.js.map +1 -0
- package/dist/admin/methods.js +83 -38
- package/dist/admin/methods.js.map +1 -1
- package/dist/admin/socket.js +2 -2
- package/dist/admin/socket.js.map +1 -1
- package/dist/channel/feishu-gate.js +187 -18
- package/dist/channel/feishu-gate.js.map +1 -1
- package/dist/channel/feishu-message.js +92 -0
- package/dist/channel/feishu-message.js.map +1 -0
- package/dist/cli/doctor.js +53 -58
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/dreamux.js +72 -61
- package/dist/cli/dreamux.js.map +1 -1
- package/dist/cli/server-ctl.js +6 -8
- package/dist/cli/server-ctl.js.map +1 -1
- package/dist/cli/server.js +25 -38
- package/dist/cli/server.js.map +1 -1
- package/dist/codex/events.js +3 -2
- package/dist/codex/events.js.map +1 -1
- package/dist/codex/mcp-config.js +24 -0
- package/dist/codex/mcp-config.js.map +1 -0
- package/dist/codex/supervisor.js +16 -0
- package/dist/codex/supervisor.js.map +1 -1
- package/dist/dispatcher/approval.js +2 -3
- package/dist/dispatcher/approval.js.map +1 -1
- package/dist/dispatcher/runtime.js +195 -143
- package/dist/dispatcher/runtime.js.map +1 -1
- package/dist/dispatcher/turn-manager.js +78 -97
- package/dist/dispatcher/turn-manager.js.map +1 -1
- package/dist/feishu/bot.js +71 -9
- package/dist/feishu/bot.js.map +1 -1
- package/dist/mcp/feishu-mcp.js +269 -0
- package/dist/mcp/feishu-mcp.js.map +1 -0
- package/dist/onboard/config-files.js +60 -87
- package/dist/onboard/config-files.js.map +1 -1
- package/dist/onboard/dispatcher-skill.js +18 -0
- package/dist/onboard/dispatcher-skill.js.map +1 -0
- package/dist/onboard/run.js +40 -79
- package/dist/onboard/run.js.map +1 -1
- package/dist/onboard/service.js +6 -5
- package/dist/onboard/service.js.map +1 -1
- package/dist/onboard/uninstall.js +161 -0
- package/dist/onboard/uninstall.js.map +1 -0
- package/dist/onboard/wizard.js +12 -69
- package/dist/onboard/wizard.js.map +1 -1
- package/dist/runtime/codex-args.js +1 -1
- package/dist/runtime/config.js +213 -213
- package/dist/runtime/config.js.map +1 -1
- package/dist/runtime/dispatcher-codex-home.js +21 -185
- package/dist/runtime/dispatcher-codex-home.js.map +1 -1
- package/dist/runtime/dispatcher-id.js +9 -0
- package/dist/runtime/dispatcher-id.js.map +1 -0
- package/dist/runtime/dispatcher-store.js +202 -0
- package/dist/runtime/dispatcher-store.js.map +1 -0
- package/dist/runtime/package-bin.js +41 -0
- package/dist/runtime/package-bin.js.map +1 -0
- package/dist/runtime/paths.js +87 -48
- package/dist/runtime/paths.js.map +1 -1
- package/dist/runtime/secrets.js +17 -14
- package/dist/runtime/secrets.js.map +1 -1
- package/dist/server.js +112 -38
- package/dist/server.js.map +1 -1
- package/package.json +6 -6
- package/skills/dispatcher/SKILL.md +107 -0
- package/db/migrations/0001_init.sql +0 -49
- package/dist/channel/outbound.js +0 -12
- package/dist/channel/outbound.js.map +0 -1
- package/dist/db/repository.js +0 -223
- package/dist/db/repository.js.map +0 -1
- package/dist/db/schema.js +0 -29
- package/dist/db/schema.js.map +0 -1
- package/dist/db/types.js +0 -2
- package/dist/db/types.js.map +0 -1
- package/dist/onboard/plugins.js +0 -202
- package/dist/onboard/plugins.js.map +0 -1
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dispatcher
|
|
3
|
+
description: Use from a dreamux dispatcher thread when work should be delegated to a tm-managed Codex teammate in a specific repository. Applies to bounded engineering tasks, test runs, codebase inspections, or follow-up work where the dispatcher should spawn/send/wait through the tm CLI exposed by the dreamux package and report the result back to the source chat.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Dispatcher
|
|
7
|
+
|
|
8
|
+
Use this skill only from the dispatcher agent. The dreamux server hosts the
|
|
9
|
+
dispatcher lifecycle; it does not own tm teammate daemons, teammate DB rows, or
|
|
10
|
+
`teammate.*` admin methods.
|
|
11
|
+
|
|
12
|
+
## Boundaries
|
|
13
|
+
|
|
14
|
+
- Use `tm` from the dispatcher environment PATH. dreamux injects its package
|
|
15
|
+
`bin/` directory into the dispatcher Codex app-server PATH.
|
|
16
|
+
- Pass `--engine codex` on every `tm spawn`; `tm spawn` defaults to Claude.
|
|
17
|
+
- Do not use `npx`, `npm exec --package @excitedjs/tm`, or
|
|
18
|
+
`@excitedjs/tm@latest`; the dreamux package owns the tm dependency version.
|
|
19
|
+
- Do not call dreamux admin APIs to create teammate state.
|
|
20
|
+
- Do not infer the tm repo path from the dispatcher cwd unless the user or
|
|
21
|
+
operator explicitly made that cwd the requested repo.
|
|
22
|
+
- Do not ask a tm-managed teammate to spawn another tm teammate.
|
|
23
|
+
|
|
24
|
+
## Before Delegating
|
|
25
|
+
|
|
26
|
+
Delegate when the request is bounded and can be completed by one teammate:
|
|
27
|
+
running tests, inspecting a code path, drafting a narrow patch, or collecting a
|
|
28
|
+
specific result. Handle the work directly when the request is tiny, ambiguous,
|
|
29
|
+
security-sensitive, or missing a repository path.
|
|
30
|
+
|
|
31
|
+
Resolve the repo path in this order:
|
|
32
|
+
|
|
33
|
+
1. An absolute path in the user request.
|
|
34
|
+
2. `TM_DISPATCHER_DIR`, if set by the operator.
|
|
35
|
+
3. Ask the user for the repo path. Do not guess.
|
|
36
|
+
|
|
37
|
+
Use an absolute repo path for `tm spawn`. If the user gives a relative path,
|
|
38
|
+
make it absolute only when its base is explicit.
|
|
39
|
+
|
|
40
|
+
## Command Shape
|
|
41
|
+
|
|
42
|
+
Preflight once per dispatcher session:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
tm --help
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## First-Turn Delegation
|
|
49
|
+
|
|
50
|
+
1. Pick a flat teammate name: lowercase letters, digits, and hyphens; keep it
|
|
51
|
+
short and tied to the task, such as `tests-api` or `scan-auth`.
|
|
52
|
+
2. Spawn with the repo path, intent, and the full task prompt:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
tm spawn /absolute/repo \
|
|
56
|
+
--name tests-api \
|
|
57
|
+
--engine codex \
|
|
58
|
+
--timeout 180 \
|
|
59
|
+
--intent "Run focused API tests and summarize failures" \
|
|
60
|
+
--prompt "Run the focused API tests. Report commands, failures, and the smallest next fix."
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
3. If `tm spawn` exits `0`, use its printed reply as the teammate result. If it
|
|
64
|
+
exits `124`, the Codex turn did not finish within the sync window; wait
|
|
65
|
+
without `--fresh`:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
tm wait tests-api --timeout 180
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
4. Reply to the source chat with the teammate result, including the command
|
|
72
|
+
summary and any explicit failure.
|
|
73
|
+
|
|
74
|
+
## Follow-Up Delegation
|
|
75
|
+
|
|
76
|
+
If a teammate name already exists for the same task, send a follow-up instead
|
|
77
|
+
of spawning a duplicate:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
tm send tests-api \
|
|
81
|
+
--prompt "Use the previous context. Re-run the focused test after the latest fix and summarize only changed results."
|
|
82
|
+
tm wait tests-api --timeout 180
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Failure Reporting
|
|
86
|
+
|
|
87
|
+
When a tm command fails, stop the delegation sequence and report:
|
|
88
|
+
|
|
89
|
+
- which `tm` verb failed
|
|
90
|
+
- the teammate name and repo path
|
|
91
|
+
- the exit status if available
|
|
92
|
+
- the first useful stderr/stdout lines
|
|
93
|
+
- whether retrying the same teammate is safe
|
|
94
|
+
|
|
95
|
+
Known early startup failure to report verbatim:
|
|
96
|
+
|
|
97
|
+
```text
|
|
98
|
+
codex daemon (pid N) exited before binding /tmp/teammate-codex/<name>/socket
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
That means the Codex app-server daemon did not become reachable. Do not retry
|
|
102
|
+
silently; report the environment failure and ask the operator to verify
|
|
103
|
+
`codex app-server --listen unix:///tmp/dispatcher-check.sock` in the dispatcher
|
|
104
|
+
environment.
|
|
105
|
+
|
|
106
|
+
Do not say the dreamux server lost or recovered teammate state. The server does
|
|
107
|
+
not own that state.
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
-- dreamux MVP schema (issue excitedjs/dreamux#2)
|
|
2
|
-
-- Version tracked via PRAGMA user_version, not a schema_version table.
|
|
3
|
-
|
|
4
|
-
CREATE TABLE dispatchers (
|
|
5
|
-
dispatcher_id TEXT PRIMARY KEY,
|
|
6
|
-
bot_app_id TEXT NOT NULL UNIQUE,
|
|
7
|
-
bot_secret_ref TEXT NOT NULL,
|
|
8
|
-
codex_args_json TEXT NOT NULL DEFAULT '{}',
|
|
9
|
-
codex_cwd TEXT,
|
|
10
|
-
thread_id TEXT,
|
|
11
|
-
status TEXT NOT NULL DEFAULT 'declared'
|
|
12
|
-
CHECK (status IN ('declared','starting','ready','degraded','stopping','stopped')),
|
|
13
|
-
enabled INTEGER NOT NULL DEFAULT 1,
|
|
14
|
-
created_at INTEGER NOT NULL,
|
|
15
|
-
updated_at INTEGER NOT NULL,
|
|
16
|
-
last_started_at INTEGER,
|
|
17
|
-
last_ready_at INTEGER,
|
|
18
|
-
last_error TEXT,
|
|
19
|
-
last_lost_thread_id TEXT
|
|
20
|
-
);
|
|
21
|
-
|
|
22
|
-
CREATE TABLE inbound_buffer (
|
|
23
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
24
|
-
dispatcher_id TEXT NOT NULL REFERENCES dispatchers(dispatcher_id),
|
|
25
|
-
source_chat_id TEXT NOT NULL,
|
|
26
|
-
source_message_id TEXT,
|
|
27
|
-
sender_id TEXT,
|
|
28
|
-
feishu_event_json TEXT NOT NULL,
|
|
29
|
-
parsed_text TEXT NOT NULL,
|
|
30
|
-
state TEXT NOT NULL DEFAULT 'queued'
|
|
31
|
-
CHECK (state IN ('queued','running','awaiting_outbound',
|
|
32
|
-
'completed','outbound_failed','failed','unknown')),
|
|
33
|
-
codex_turn_id TEXT,
|
|
34
|
-
assistant_text TEXT,
|
|
35
|
-
feishu_message_ids_json TEXT,
|
|
36
|
-
outbound_error TEXT,
|
|
37
|
-
received_at INTEGER NOT NULL,
|
|
38
|
-
started_at INTEGER,
|
|
39
|
-
completed_at INTEGER,
|
|
40
|
-
failed_at INTEGER,
|
|
41
|
-
error TEXT
|
|
42
|
-
);
|
|
43
|
-
|
|
44
|
-
CREATE INDEX idx_inbound_dispatcher_state
|
|
45
|
-
ON inbound_buffer(dispatcher_id, state, id);
|
|
46
|
-
|
|
47
|
-
CREATE UNIQUE INDEX idx_inbound_message_dedupe
|
|
48
|
-
ON inbound_buffer(dispatcher_id, source_message_id)
|
|
49
|
-
WHERE source_message_id IS NOT NULL;
|
package/dist/channel/outbound.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
export function outboundTargetForInbound(row) {
|
|
2
|
-
return {
|
|
3
|
-
conversationId: row.source_chat_id,
|
|
4
|
-
...(row.source_message_id !== null
|
|
5
|
-
? { replyTo: row.source_message_id }
|
|
6
|
-
: {}),
|
|
7
|
-
...(row.sender_id !== null && row.sender_id !== ''
|
|
8
|
-
? { mentionUsers: [row.sender_id] }
|
|
9
|
-
: {}),
|
|
10
|
-
};
|
|
11
|
-
}
|
|
12
|
-
//# sourceMappingURL=outbound.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"outbound.js","sourceRoot":"","sources":["../../src/channel/outbound.ts"],"names":[],"mappings":"AAkBA,MAAM,UAAU,wBAAwB,CAAC,GAAe;IACtD,OAAO;QACL,cAAc,EAAE,GAAG,CAAC,cAAc;QAClC,GAAG,CAAC,GAAG,CAAC,iBAAiB,KAAK,IAAI;YAChC,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,iBAAiB,EAAE;YACpC,CAAC,CAAC,EAAE,CAAC;QACP,GAAG,CAAC,GAAG,CAAC,SAAS,KAAK,IAAI,IAAI,GAAG,CAAC,SAAS,KAAK,EAAE;YAChD,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE;YACnC,CAAC,CAAC,EAAE,CAAC;KACR,CAAC;AACJ,CAAC"}
|
package/dist/db/repository.js
DELETED
|
@@ -1,223 +0,0 @@
|
|
|
1
|
-
const DISPATCHER_COLUMNS = `
|
|
2
|
-
dispatcher_id, bot_app_id, bot_secret_ref, codex_args_json, codex_cwd,
|
|
3
|
-
thread_id, status, enabled, created_at, updated_at,
|
|
4
|
-
last_started_at, last_ready_at, last_error, last_lost_thread_id
|
|
5
|
-
`;
|
|
6
|
-
const INBOUND_COLUMNS = `
|
|
7
|
-
id, dispatcher_id, source_chat_id, source_message_id, sender_id,
|
|
8
|
-
feishu_event_json, parsed_text, state, codex_turn_id, assistant_text,
|
|
9
|
-
feishu_message_ids_json, outbound_error, received_at, started_at,
|
|
10
|
-
completed_at, failed_at, error
|
|
11
|
-
`;
|
|
12
|
-
export class DispatcherRepo {
|
|
13
|
-
db;
|
|
14
|
-
constructor(db) {
|
|
15
|
-
this.db = db;
|
|
16
|
-
}
|
|
17
|
-
create(input) {
|
|
18
|
-
const now = Date.now();
|
|
19
|
-
this.db
|
|
20
|
-
.prepare(`INSERT INTO dispatchers (
|
|
21
|
-
dispatcher_id, bot_app_id, bot_secret_ref, codex_args_json,
|
|
22
|
-
codex_cwd, status, enabled, created_at, updated_at
|
|
23
|
-
) VALUES (?, ?, ?, ?, ?, 'declared', 1, ?, ?)`)
|
|
24
|
-
.run(input.dispatcher_id, input.bot_app_id, input.bot_secret_ref, input.codex_args_json ?? '{}', input.codex_cwd ?? null, now, now);
|
|
25
|
-
return this.get(input.dispatcher_id);
|
|
26
|
-
}
|
|
27
|
-
upsert(input) {
|
|
28
|
-
const existing = this.get(input.dispatcher_id);
|
|
29
|
-
if (existing === null)
|
|
30
|
-
return this.create(input);
|
|
31
|
-
this.db
|
|
32
|
-
.prepare(`UPDATE dispatchers
|
|
33
|
-
SET bot_app_id = ?,
|
|
34
|
-
bot_secret_ref = ?,
|
|
35
|
-
codex_args_json = ?,
|
|
36
|
-
codex_cwd = ?,
|
|
37
|
-
enabled = 1,
|
|
38
|
-
updated_at = ?
|
|
39
|
-
WHERE dispatcher_id = ?`)
|
|
40
|
-
.run(input.bot_app_id, input.bot_secret_ref, input.codex_args_json ?? '{}', input.codex_cwd ?? null, Date.now(), input.dispatcher_id);
|
|
41
|
-
return this.get(input.dispatcher_id);
|
|
42
|
-
}
|
|
43
|
-
get(id) {
|
|
44
|
-
const row = this.db
|
|
45
|
-
.prepare(`SELECT ${DISPATCHER_COLUMNS} FROM dispatchers WHERE dispatcher_id = ?`)
|
|
46
|
-
.get(id);
|
|
47
|
-
return row ?? null;
|
|
48
|
-
}
|
|
49
|
-
list() {
|
|
50
|
-
return this.db
|
|
51
|
-
.prepare(`SELECT ${DISPATCHER_COLUMNS} FROM dispatchers ORDER BY created_at ASC`)
|
|
52
|
-
.all();
|
|
53
|
-
}
|
|
54
|
-
listEnabled() {
|
|
55
|
-
return this.db
|
|
56
|
-
.prepare(`SELECT ${DISPATCHER_COLUMNS} FROM dispatchers WHERE enabled = 1 ORDER BY created_at ASC`)
|
|
57
|
-
.all();
|
|
58
|
-
}
|
|
59
|
-
remove(id) {
|
|
60
|
-
const tx = this.db.transaction(() => {
|
|
61
|
-
this.db
|
|
62
|
-
.prepare(`DELETE FROM inbound_buffer WHERE dispatcher_id = ?`)
|
|
63
|
-
.run(id);
|
|
64
|
-
this.db.prepare(`DELETE FROM dispatchers WHERE dispatcher_id = ?`).run(id);
|
|
65
|
-
});
|
|
66
|
-
tx();
|
|
67
|
-
}
|
|
68
|
-
setStatus(id, status, extras = {}) {
|
|
69
|
-
const fields = ['status = ?', 'updated_at = ?'];
|
|
70
|
-
const values = [status, Date.now()];
|
|
71
|
-
if ('last_error' in extras) {
|
|
72
|
-
fields.push('last_error = ?');
|
|
73
|
-
values.push(extras.last_error ?? null);
|
|
74
|
-
}
|
|
75
|
-
if (extras.last_started_at !== undefined) {
|
|
76
|
-
fields.push('last_started_at = ?');
|
|
77
|
-
values.push(extras.last_started_at);
|
|
78
|
-
}
|
|
79
|
-
if (extras.last_ready_at !== undefined) {
|
|
80
|
-
fields.push('last_ready_at = ?');
|
|
81
|
-
values.push(extras.last_ready_at);
|
|
82
|
-
}
|
|
83
|
-
values.push(id);
|
|
84
|
-
this.db
|
|
85
|
-
.prepare(`UPDATE dispatchers SET ${fields.join(', ')} WHERE dispatcher_id = ?`)
|
|
86
|
-
.run(...values);
|
|
87
|
-
}
|
|
88
|
-
setThreadId(id, threadId) {
|
|
89
|
-
this.db
|
|
90
|
-
.prepare(`UPDATE dispatchers SET thread_id = ?, updated_at = ? WHERE dispatcher_id = ?`)
|
|
91
|
-
.run(threadId, Date.now(), id);
|
|
92
|
-
}
|
|
93
|
-
recordLostThread(id, lostThreadId, newThreadId, error) {
|
|
94
|
-
this.db
|
|
95
|
-
.prepare(`UPDATE dispatchers
|
|
96
|
-
SET thread_id = ?, last_lost_thread_id = ?, last_error = ?, updated_at = ?
|
|
97
|
-
WHERE dispatcher_id = ?`)
|
|
98
|
-
.run(newThreadId, lostThreadId, error, Date.now(), id);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
export class InboundRepo {
|
|
102
|
-
db;
|
|
103
|
-
constructor(db) {
|
|
104
|
-
this.db = db;
|
|
105
|
-
}
|
|
106
|
-
/** Returns null when this message was already buffered (dedupe). */
|
|
107
|
-
enqueue(input) {
|
|
108
|
-
try {
|
|
109
|
-
const now = Date.now();
|
|
110
|
-
const result = this.db
|
|
111
|
-
.prepare(`INSERT INTO inbound_buffer (
|
|
112
|
-
dispatcher_id, source_chat_id, source_message_id, sender_id,
|
|
113
|
-
feishu_event_json, parsed_text, state, received_at
|
|
114
|
-
) VALUES (?, ?, ?, ?, ?, ?, 'queued', ?)`)
|
|
115
|
-
.run(input.dispatcher_id, input.source_chat_id, input.source_message_id, input.sender_id, input.feishu_event_json, input.parsed_text, now);
|
|
116
|
-
return this.getById(Number(result.lastInsertRowid));
|
|
117
|
-
}
|
|
118
|
-
catch (err) {
|
|
119
|
-
if (isUniqueViolation(err))
|
|
120
|
-
return null;
|
|
121
|
-
throw err;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
getById(id) {
|
|
125
|
-
const row = this.db
|
|
126
|
-
.prepare(`SELECT ${INBOUND_COLUMNS} FROM inbound_buffer WHERE id = ?`)
|
|
127
|
-
.get(id);
|
|
128
|
-
return row ?? null;
|
|
129
|
-
}
|
|
130
|
-
/** Pull the oldest queued row for a dispatcher; returns null if none. */
|
|
131
|
-
takeNextQueued(dispatcherId) {
|
|
132
|
-
const row = this.db
|
|
133
|
-
.prepare(`SELECT ${INBOUND_COLUMNS} FROM inbound_buffer
|
|
134
|
-
WHERE dispatcher_id = ? AND state = 'queued'
|
|
135
|
-
ORDER BY id ASC LIMIT 1`)
|
|
136
|
-
.get(dispatcherId);
|
|
137
|
-
return row ?? null;
|
|
138
|
-
}
|
|
139
|
-
markRunning(id, turnId) {
|
|
140
|
-
this.db
|
|
141
|
-
.prepare(`UPDATE inbound_buffer
|
|
142
|
-
SET state = 'running', started_at = ?, codex_turn_id = ?
|
|
143
|
-
WHERE id = ? AND state = 'queued'`)
|
|
144
|
-
.run(Date.now(), turnId, id);
|
|
145
|
-
}
|
|
146
|
-
markAwaitingOutbound(id, assistantText) {
|
|
147
|
-
this.db
|
|
148
|
-
.prepare(`UPDATE inbound_buffer
|
|
149
|
-
SET state = 'awaiting_outbound', assistant_text = ?
|
|
150
|
-
WHERE id = ?`)
|
|
151
|
-
.run(assistantText, id);
|
|
152
|
-
}
|
|
153
|
-
markCompleted(id, feishuMessageIds) {
|
|
154
|
-
this.db
|
|
155
|
-
.prepare(`UPDATE inbound_buffer
|
|
156
|
-
SET state = 'completed', feishu_message_ids_json = ?, completed_at = ?
|
|
157
|
-
WHERE id = ?`)
|
|
158
|
-
.run(JSON.stringify(feishuMessageIds), Date.now(), id);
|
|
159
|
-
}
|
|
160
|
-
markOutboundFailed(id, error) {
|
|
161
|
-
this.db
|
|
162
|
-
.prepare(`UPDATE inbound_buffer
|
|
163
|
-
SET state = 'outbound_failed', outbound_error = ?
|
|
164
|
-
WHERE id = ?`)
|
|
165
|
-
.run(error, id);
|
|
166
|
-
}
|
|
167
|
-
markFailed(id, error) {
|
|
168
|
-
this.db
|
|
169
|
-
.prepare(`UPDATE inbound_buffer
|
|
170
|
-
SET state = 'failed', error = ?, failed_at = ?
|
|
171
|
-
WHERE id = ?`)
|
|
172
|
-
.run(error, Date.now(), id);
|
|
173
|
-
}
|
|
174
|
-
/** Crash recovery: anything still 'running' from a previous server life. */
|
|
175
|
-
markRunningAsUnknown(dispatcherId) {
|
|
176
|
-
const rows = this.db
|
|
177
|
-
.prepare(`SELECT ${INBOUND_COLUMNS} FROM inbound_buffer
|
|
178
|
-
WHERE dispatcher_id = ? AND state = 'running'`)
|
|
179
|
-
.all(dispatcherId);
|
|
180
|
-
if (rows.length === 0)
|
|
181
|
-
return [];
|
|
182
|
-
const now = Date.now();
|
|
183
|
-
this.db
|
|
184
|
-
.prepare(`UPDATE inbound_buffer
|
|
185
|
-
SET state = 'unknown', error = 'server restarted while turn was running', failed_at = ?
|
|
186
|
-
WHERE dispatcher_id = ? AND state = 'running'`)
|
|
187
|
-
.run(now, dispatcherId);
|
|
188
|
-
return rows;
|
|
189
|
-
}
|
|
190
|
-
/** Crash recovery: turn finished but outbound never completed (safe to retry). */
|
|
191
|
-
listAwaitingOrFailedOutbound(dispatcherId) {
|
|
192
|
-
return this.db
|
|
193
|
-
.prepare(`SELECT ${INBOUND_COLUMNS} FROM inbound_buffer
|
|
194
|
-
WHERE dispatcher_id = ? AND state IN ('awaiting_outbound','outbound_failed')
|
|
195
|
-
ORDER BY id ASC`)
|
|
196
|
-
.all(dispatcherId);
|
|
197
|
-
}
|
|
198
|
-
countByState(dispatcherId) {
|
|
199
|
-
const rows = this.db
|
|
200
|
-
.prepare(`SELECT state, COUNT(*) AS n FROM inbound_buffer
|
|
201
|
-
WHERE dispatcher_id = ? GROUP BY state`)
|
|
202
|
-
.all(dispatcherId);
|
|
203
|
-
const out = {
|
|
204
|
-
queued: 0,
|
|
205
|
-
running: 0,
|
|
206
|
-
awaiting_outbound: 0,
|
|
207
|
-
completed: 0,
|
|
208
|
-
outbound_failed: 0,
|
|
209
|
-
failed: 0,
|
|
210
|
-
unknown: 0,
|
|
211
|
-
};
|
|
212
|
-
for (const r of rows)
|
|
213
|
-
out[r.state] = r.n;
|
|
214
|
-
return out;
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
function isUniqueViolation(err) {
|
|
218
|
-
if (!err || typeof err !== 'object')
|
|
219
|
-
return false;
|
|
220
|
-
const code = err.code;
|
|
221
|
-
return code === 'SQLITE_CONSTRAINT_UNIQUE' || code === 'SQLITE_CONSTRAINT_PRIMARYKEY';
|
|
222
|
-
}
|
|
223
|
-
//# sourceMappingURL=repository.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"repository.js","sourceRoot":"","sources":["../../src/db/repository.ts"],"names":[],"mappings":"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"}
|
package/dist/db/schema.js
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import Database from 'better-sqlite3';
|
|
2
|
-
import { readFileSync } from 'node:fs';
|
|
3
|
-
import { dirname, join } from 'node:path';
|
|
4
|
-
import { fileURLToPath } from 'node:url';
|
|
5
|
-
const CURRENT_USER_VERSION = 1;
|
|
6
|
-
const here = dirname(fileURLToPath(import.meta.url));
|
|
7
|
-
const migrationsDir = join(here, '..', '..', 'db', 'migrations');
|
|
8
|
-
export function openDatabase(opts) {
|
|
9
|
-
const db = new Database(opts.path);
|
|
10
|
-
db.pragma('journal_mode = WAL');
|
|
11
|
-
db.pragma('foreign_keys = ON');
|
|
12
|
-
db.pragma('busy_timeout = 5000');
|
|
13
|
-
migrateIfNeeded(db);
|
|
14
|
-
return db;
|
|
15
|
-
}
|
|
16
|
-
function migrateIfNeeded(db) {
|
|
17
|
-
const row = db.pragma('user_version', { simple: true });
|
|
18
|
-
if (row >= CURRENT_USER_VERSION)
|
|
19
|
-
return;
|
|
20
|
-
const tx = db.transaction(() => {
|
|
21
|
-
if (row < 1) {
|
|
22
|
-
const sql = readFileSync(join(migrationsDir, '0001_init.sql'), 'utf8');
|
|
23
|
-
db.exec(sql);
|
|
24
|
-
}
|
|
25
|
-
db.pragma(`user_version = ${CURRENT_USER_VERSION}`);
|
|
26
|
-
});
|
|
27
|
-
tx();
|
|
28
|
-
}
|
|
29
|
-
//# sourceMappingURL=schema.js.map
|
package/dist/db/schema.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/db/schema.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,oBAAoB,GAAG,CAAC,CAAC;AAE/B,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACrD,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,YAAY,CAAC,CAAC;AAMjE,MAAM,UAAU,YAAY,CAAC,IAAmB;IAC9C,MAAM,EAAE,GAAG,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnC,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAChC,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC;IAC/B,EAAE,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC;IACjC,eAAe,CAAC,EAAE,CAAC,CAAC;IACpB,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,SAAS,eAAe,CAAC,EAAqB;IAC5C,MAAM,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,cAAc,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAW,CAAC;IAClE,IAAI,GAAG,IAAI,oBAAoB;QAAE,OAAO;IAExC,MAAM,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE;QAC7B,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC;YACZ,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,aAAa,EAAE,eAAe,CAAC,EAAE,MAAM,CAAC,CAAC;YACvE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACf,CAAC;QACD,EAAE,CAAC,MAAM,CAAC,kBAAkB,oBAAoB,EAAE,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IACH,EAAE,EAAE,CAAC;AACP,CAAC"}
|
package/dist/db/types.js
DELETED
package/dist/db/types.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/db/types.ts"],"names":[],"mappings":""}
|
package/dist/onboard/plugins.js
DELETED
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
import { existsSync, readFileSync, readdirSync, statSync, } from 'node:fs';
|
|
2
|
-
import { basename, join } from 'node:path';
|
|
3
|
-
import { parse as parseToml } from 'smol-toml';
|
|
4
|
-
import { ensureDirectory, recordFileTreeChanges, snapshotFiles, } from './ledger.js';
|
|
5
|
-
export async function installCodexmuxPlugin(options) {
|
|
6
|
-
ensureDirectory(options.codexHome, options.ledger, 'dispatcher CODEX_HOME', {
|
|
7
|
-
dryRun: options.answers.dryRun,
|
|
8
|
-
});
|
|
9
|
-
const before = snapshotFiles(options.codexHome);
|
|
10
|
-
const env = { ...process.env, CODEX_HOME: options.codexHome };
|
|
11
|
-
if (!codexMarketplaceConfigured(options)) {
|
|
12
|
-
await options.runner.run(options.answers.codexBin, [
|
|
13
|
-
'plugin',
|
|
14
|
-
'marketplace',
|
|
15
|
-
'add',
|
|
16
|
-
options.answers.codexMarketplaceSource,
|
|
17
|
-
...sparseArgs(options.answers.codexMarketplaceSparse),
|
|
18
|
-
], {
|
|
19
|
-
env,
|
|
20
|
-
dryRun: options.answers.dryRun,
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
if (!codexPluginInstalled(options.codexHome, options.answers.codexPluginRef)) {
|
|
24
|
-
await options.runner.run(options.answers.codexBin, ['plugin', 'add', options.answers.codexPluginRef], {
|
|
25
|
-
env,
|
|
26
|
-
dryRun: options.answers.dryRun,
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
recordFileTreeChanges(options.codexHome, before, options.ledger, 'codex plugin install');
|
|
30
|
-
if (!options.answers.dryRun &&
|
|
31
|
-
!codexPluginInstalled(options.codexHome, options.answers.codexPluginRef)) {
|
|
32
|
-
throw new Error(`codex plugin install did not produce ${pluginName(options.answers.codexPluginRef)} under ${join(options.codexHome, 'plugins')}`);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
export async function installClaudemuxPlugin(options) {
|
|
36
|
-
ensureDirectory(options.answers.claudeConfigDir, options.ledger, 'Claude config directory', { dryRun: options.answers.dryRun });
|
|
37
|
-
const before = snapshotFiles(options.answers.claudeConfigDir);
|
|
38
|
-
const env = {
|
|
39
|
-
...process.env,
|
|
40
|
-
CLAUDE_CONFIG_DIR: options.answers.claudeConfigDir,
|
|
41
|
-
};
|
|
42
|
-
const installedBefore = await claudePluginInstalled(options, env);
|
|
43
|
-
if (!installedBefore) {
|
|
44
|
-
if (!claudeMarketplaceConfigured(options.answers)) {
|
|
45
|
-
await options.runner.run(options.answers.claudeBin, [
|
|
46
|
-
'plugin',
|
|
47
|
-
'marketplace',
|
|
48
|
-
'add',
|
|
49
|
-
options.answers.claudeMarketplaceSource,
|
|
50
|
-
...sparseArgs(options.answers.claudeMarketplaceSparse),
|
|
51
|
-
'--scope',
|
|
52
|
-
'user',
|
|
53
|
-
], { env, dryRun: options.answers.dryRun });
|
|
54
|
-
}
|
|
55
|
-
await options.runner.run(options.answers.claudeBin, ['plugin', 'install', options.answers.claudePluginRef, '--scope', 'user'], { env, dryRun: options.answers.dryRun });
|
|
56
|
-
}
|
|
57
|
-
recordFileTreeChanges(options.answers.claudeConfigDir, before, options.ledger, 'claude plugin install');
|
|
58
|
-
if (!options.answers.dryRun && !(await claudePluginInstalled(options, env))) {
|
|
59
|
-
throw new Error(`claude plugin install did not report ${options.answers.claudePluginRef} in claude plugin list --json`);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
function sparseArgs(paths) {
|
|
63
|
-
return paths.flatMap((path) => ['--sparse', path]);
|
|
64
|
-
}
|
|
65
|
-
function codexMarketplaceConfigured(options) {
|
|
66
|
-
const configPath = join(options.codexHome, 'config.toml');
|
|
67
|
-
if (!existsSync(configPath))
|
|
68
|
-
return false;
|
|
69
|
-
try {
|
|
70
|
-
const parsed = parseToml(readFileSync(configPath, 'utf8'));
|
|
71
|
-
const marketplaces = recordValue(recordValue(parsed)['marketplaces']);
|
|
72
|
-
const marketplace = recordValue(marketplaces[options.answers.codexMarketplaceName]);
|
|
73
|
-
return marketplace['source'] === options.answers.codexMarketplaceSource;
|
|
74
|
-
}
|
|
75
|
-
catch {
|
|
76
|
-
return false;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
function codexPluginInstalled(codexHome, ref) {
|
|
80
|
-
return hasPathSegment(join(codexHome, 'plugins'), pluginName(ref), 6);
|
|
81
|
-
}
|
|
82
|
-
function claudeMarketplaceConfigured(answers) {
|
|
83
|
-
return (claudeSettingsHasMarketplace(answers) ||
|
|
84
|
-
claudeKnownMarketplacesHasMarketplace(answers));
|
|
85
|
-
}
|
|
86
|
-
function claudeSettingsHasMarketplace(answers) {
|
|
87
|
-
const settingsPath = join(answers.claudeConfigDir, 'settings.json');
|
|
88
|
-
const parsed = readJsonObject(settingsPath);
|
|
89
|
-
if (parsed === null)
|
|
90
|
-
return false;
|
|
91
|
-
const marketplaces = recordValue(parsed['extraKnownMarketplaces']);
|
|
92
|
-
const marketplace = recordValue(marketplaces[answers.claudeMarketplaceName]);
|
|
93
|
-
return claudeMarketplaceSourceMatches(marketplace, answers);
|
|
94
|
-
}
|
|
95
|
-
function claudeKnownMarketplacesHasMarketplace(answers) {
|
|
96
|
-
const knownPath = join(answers.claudeConfigDir, 'plugins', 'known_marketplaces.json');
|
|
97
|
-
const parsed = readJsonObject(knownPath);
|
|
98
|
-
if (parsed === null)
|
|
99
|
-
return false;
|
|
100
|
-
const marketplace = recordValue(parsed[answers.claudeMarketplaceName]);
|
|
101
|
-
return claudeMarketplaceSourceMatches(marketplace, answers);
|
|
102
|
-
}
|
|
103
|
-
function claudeMarketplaceSourceMatches(marketplace, answers) {
|
|
104
|
-
if (Object.keys(marketplace).length === 0)
|
|
105
|
-
return false;
|
|
106
|
-
const source = recordValue(marketplace['source']);
|
|
107
|
-
const directSource = stringValue(marketplace['source']);
|
|
108
|
-
if (directSource === answers.claudeMarketplaceSource)
|
|
109
|
-
return true;
|
|
110
|
-
const repo = stringValue(source['repo']);
|
|
111
|
-
if (repo === answers.claudeMarketplaceSource)
|
|
112
|
-
return true;
|
|
113
|
-
const path = stringValue(source['path']);
|
|
114
|
-
if (path === answers.claudeMarketplaceSource)
|
|
115
|
-
return true;
|
|
116
|
-
const url = stringValue(source['url']);
|
|
117
|
-
if (url === answers.claudeMarketplaceSource)
|
|
118
|
-
return true;
|
|
119
|
-
return false;
|
|
120
|
-
}
|
|
121
|
-
async function claudePluginInstalled(options, env) {
|
|
122
|
-
if (options.answers.dryRun)
|
|
123
|
-
return false;
|
|
124
|
-
let raw;
|
|
125
|
-
try {
|
|
126
|
-
raw = await options.runner.capture(options.answers.claudeBin, ['plugin', 'list', '--json'], { env });
|
|
127
|
-
}
|
|
128
|
-
catch {
|
|
129
|
-
return false;
|
|
130
|
-
}
|
|
131
|
-
let parsed;
|
|
132
|
-
try {
|
|
133
|
-
parsed = JSON.parse(raw);
|
|
134
|
-
}
|
|
135
|
-
catch {
|
|
136
|
-
return false;
|
|
137
|
-
}
|
|
138
|
-
if (!Array.isArray(parsed))
|
|
139
|
-
return false;
|
|
140
|
-
const expected = pluginName(options.answers.claudePluginRef);
|
|
141
|
-
const expectedRef = options.answers.claudePluginRef;
|
|
142
|
-
return parsed.some((item) => {
|
|
143
|
-
const record = recordValue(item);
|
|
144
|
-
return [record['name'], record['id'], record['plugin'], record['ref']].some((value) => value === expected || value === expectedRef);
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
function pluginName(ref) {
|
|
148
|
-
return ref.split('@')[0] ?? ref;
|
|
149
|
-
}
|
|
150
|
-
function hasPathSegment(root, segment, maxDepth) {
|
|
151
|
-
if (!existsSync(root))
|
|
152
|
-
return false;
|
|
153
|
-
const stack = [{ path: root, depth: 0 }];
|
|
154
|
-
while (stack.length > 0) {
|
|
155
|
-
const current = stack.pop();
|
|
156
|
-
if (current === undefined)
|
|
157
|
-
continue;
|
|
158
|
-
if (basename(current.path) === segment)
|
|
159
|
-
return true;
|
|
160
|
-
if (current.depth >= maxDepth)
|
|
161
|
-
continue;
|
|
162
|
-
let entries;
|
|
163
|
-
try {
|
|
164
|
-
entries = readdirSync(current.path);
|
|
165
|
-
}
|
|
166
|
-
catch {
|
|
167
|
-
continue;
|
|
168
|
-
}
|
|
169
|
-
for (const entry of entries) {
|
|
170
|
-
const child = join(current.path, entry);
|
|
171
|
-
try {
|
|
172
|
-
if (statSync(child).isDirectory()) {
|
|
173
|
-
stack.push({ path: child, depth: current.depth + 1 });
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
catch {
|
|
177
|
-
/* ignore transient filesystem races */
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
return false;
|
|
182
|
-
}
|
|
183
|
-
function recordValue(value) {
|
|
184
|
-
if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
|
|
185
|
-
return value;
|
|
186
|
-
}
|
|
187
|
-
return {};
|
|
188
|
-
}
|
|
189
|
-
function stringValue(value) {
|
|
190
|
-
return typeof value === 'string' ? value : null;
|
|
191
|
-
}
|
|
192
|
-
function readJsonObject(path) {
|
|
193
|
-
if (!existsSync(path))
|
|
194
|
-
return null;
|
|
195
|
-
try {
|
|
196
|
-
return recordValue(JSON.parse(readFileSync(path, 'utf8')));
|
|
197
|
-
}
|
|
198
|
-
catch {
|
|
199
|
-
return null;
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
//# sourceMappingURL=plugins.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"plugins.js","sourceRoot":"","sources":["../../src/onboard/plugins.ts"],"names":[],"mappings":"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"}
|