@oatelauser/crosschat 1.0.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.
Files changed (59) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/LICENSE +25 -0
  3. package/README.md +244 -0
  4. package/dist/claude/deliver.js +33 -0
  5. package/dist/claude/deliver.js.map +1 -0
  6. package/dist/claude/frame.js +16 -0
  7. package/dist/claude/frame.js.map +1 -0
  8. package/dist/claude/key-file.js +45 -0
  9. package/dist/claude/key-file.js.map +1 -0
  10. package/dist/claude/registry.js +79 -0
  11. package/dist/claude/registry.js.map +1 -0
  12. package/dist/claude/resolve-exe.js +31 -0
  13. package/dist/claude/resolve-exe.js.map +1 -0
  14. package/dist/cli.js +270 -0
  15. package/dist/cli.js.map +1 -0
  16. package/dist/codex/client.js +130 -0
  17. package/dist/codex/client.js.map +1 -0
  18. package/dist/codex/deliver.js +162 -0
  19. package/dist/codex/deliver.js.map +1 -0
  20. package/dist/codex/discovery.js +45 -0
  21. package/dist/codex/discovery.js.map +1 -0
  22. package/dist/codex/queue.js +71 -0
  23. package/dist/codex/queue.js.map +1 -0
  24. package/dist/codex/rollout-meta.js +118 -0
  25. package/dist/codex/rollout-meta.js.map +1 -0
  26. package/dist/codex/rpc.js +153 -0
  27. package/dist/codex/rpc.js.map +1 -0
  28. package/dist/codex/transport.js +357 -0
  29. package/dist/codex/transport.js.map +1 -0
  30. package/dist/commands/claude-wrapper.js +28 -0
  31. package/dist/commands/claude-wrapper.js.map +1 -0
  32. package/dist/commands/doctor.js +169 -0
  33. package/dist/commands/doctor.js.map +1 -0
  34. package/dist/commands/install-skills.js +26 -0
  35. package/dist/commands/install-skills.js.map +1 -0
  36. package/dist/commands/send.js +122 -0
  37. package/dist/commands/send.js.map +1 -0
  38. package/dist/commands/status.js +77 -0
  39. package/dist/commands/status.js.map +1 -0
  40. package/dist/envelope.js +34 -0
  41. package/dist/envelope.js.map +1 -0
  42. package/dist/errors.js +15 -0
  43. package/dist/errors.js.map +1 -0
  44. package/dist/identity.js +42 -0
  45. package/dist/identity.js.map +1 -0
  46. package/dist/outbox.js +172 -0
  47. package/dist/outbox.js.map +1 -0
  48. package/dist/platform/pipe-transport.js +73 -0
  49. package/dist/platform/pipe-transport.js.map +1 -0
  50. package/dist/platform/process-inspector.js +15 -0
  51. package/dist/platform/process-inspector.js.map +1 -0
  52. package/dist/rate-limit.js +49 -0
  53. package/dist/rate-limit.js.map +1 -0
  54. package/dist/ref.js +64 -0
  55. package/dist/ref.js.map +1 -0
  56. package/dist/resolve.js +30 -0
  57. package/dist/resolve.js.map +1 -0
  58. package/package.json +47 -0
  59. package/skills/crosschat/SKILL.md +65 -0
package/dist/cli.js ADDED
@@ -0,0 +1,270 @@
1
+ #!/usr/bin/env node
2
+ import { readFileSync, realpathSync } from 'node:fs';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { Buffer } from 'node:buffer';
5
+ import process from 'node:process';
6
+ import { MultichatError } from './errors.js';
7
+ import { runSend } from './commands/send.js';
8
+ import { runStatus } from './commands/status.js';
9
+ import { runInstallSkills } from './commands/install-skills.js';
10
+ import { runDoctor } from './commands/doctor.js';
11
+ import { runClaudeWrapper } from './commands/claude-wrapper.js';
12
+ import { defaultRateDir } from './rate-limit.js';
13
+ import { defaultOutboxDir, drain } from './outbox.js';
14
+ import { listClaudeSessions } from './claude/registry.js';
15
+ import { deliverToClaudeSession } from './claude/deliver.js';
16
+ import { listCodexThreads } from './codex/discovery.js';
17
+ import { deliverToCodexThread } from './codex/deliver.js';
18
+ const version = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version;
19
+ const usage = `usage: crosschat <command> [options]
20
+
21
+ commands:
22
+ send --to <name> | --conversation <ref>
23
+ send a message (--body <text> or stdin);
24
+ quote <name> if it contains spaces
25
+ status show claude/codex session status
26
+ doctor environment health check (exits 1 on any ❌)
27
+ install-skills [--dir <root>]
28
+ install the agent skill into <root>/.claude and
29
+ <root>/.codex (default root: home directory)
30
+ claude [args...] run the real claude CLI with inbound peer
31
+ messaging enabled; other args pass through
32
+
33
+ options:
34
+ --json single-line JSON output (send/status)
35
+ -v, --version print version and exit
36
+ --help | help show this help and exit
37
+ `;
38
+ /** Hand-rolled send arg parsing (no dependency): --to/--conversation/--body take values, --json is a flag. */
39
+ export function parseSendArgs(argv) {
40
+ const args = {};
41
+ const valueOpts = new Set(['--to', '--conversation', '--body']);
42
+ for (let i = 0; i < argv.length; i++) {
43
+ const token = argv[i];
44
+ if (token === undefined || !token.startsWith('--')) {
45
+ throw new MultichatError('USAGE', `send: unexpected argument: ${token ?? ''}`);
46
+ }
47
+ const eq = token.indexOf('=');
48
+ const name = eq > 0 ? token.slice(0, eq) : token;
49
+ const inline = eq > 0 ? token.slice(eq + 1) : undefined;
50
+ if (name === '--json') {
51
+ if (inline !== undefined)
52
+ throw new MultichatError('USAGE', 'send: --json takes no value');
53
+ args.json = true;
54
+ continue;
55
+ }
56
+ if (!valueOpts.has(name))
57
+ throw new MultichatError('USAGE', `send: unknown option: ${name}`);
58
+ const value = inline !== undefined ? inline : argv[++i];
59
+ if (value === undefined)
60
+ throw new MultichatError('USAGE', `send: ${name} requires a value`);
61
+ if (name === '--to')
62
+ args.to = value;
63
+ else if (name === '--conversation')
64
+ args.conversation = value;
65
+ else
66
+ args.bodyArg = value;
67
+ }
68
+ return args;
69
+ }
70
+ /** status accepts no options except --json. */
71
+ export function parseStatusArgs(argv) {
72
+ if (argv.length === 0)
73
+ return { json: false };
74
+ if (argv.length === 1 && argv[0] === '--json')
75
+ return { json: true };
76
+ throw new MultichatError('USAGE', `status takes only --json; got: ${argv.join(' ')}`);
77
+ }
78
+ /** install-skills accepts only --dir <root> (space or = separated). */
79
+ export function parseInstallSkillsArgs(argv) {
80
+ const args = {};
81
+ for (let i = 0; i < argv.length; i++) {
82
+ const token = argv[i];
83
+ if (token === undefined || !token.startsWith('--')) {
84
+ throw new MultichatError('USAGE', `install-skills: unexpected argument: ${token ?? ''}`);
85
+ }
86
+ const eq = token.indexOf('=');
87
+ const name = eq > 0 ? token.slice(0, eq) : token;
88
+ const inline = eq > 0 ? token.slice(eq + 1) : undefined;
89
+ if (name !== '--dir')
90
+ throw new MultichatError('USAGE', `install-skills: unknown option: ${name}`);
91
+ const value = inline !== undefined ? inline : argv[++i];
92
+ if (value === undefined)
93
+ throw new MultichatError('USAGE', 'install-skills: --dir requires a value');
94
+ args.dir = value;
95
+ }
96
+ return args;
97
+ }
98
+ function readStdinText() {
99
+ const stdin = process.stdin;
100
+ if (stdin.isTTY)
101
+ return Promise.resolve(undefined);
102
+ return new Promise((resolve, reject) => {
103
+ const chunks = [];
104
+ stdin.on('data', (chunk) => chunks.push(chunk));
105
+ stdin.on('end', () => resolve(Buffer.concat(chunks).toString('utf8') || undefined));
106
+ stdin.on('error', reject);
107
+ });
108
+ }
109
+ function realSendDeps(stdinText) {
110
+ return {
111
+ env: process.env,
112
+ stdinText,
113
+ listClaudeSessions: () => listClaudeSessions(),
114
+ listCodexThreads: () => listCodexThreads(),
115
+ deliverClaude: (target, content) => deliverToClaudeSession(target, content),
116
+ deliverCodex: (threadId, content) => deliverToCodexThread(threadId, content),
117
+ rateDir: defaultRateDir(),
118
+ outboxDir: defaultOutboxDir(),
119
+ now: () => Date.now(),
120
+ };
121
+ }
122
+ function realStatusDeps() {
123
+ return {
124
+ listClaudeSessions: () => listClaudeSessions(),
125
+ listCodexThreads: () => listCodexThreads(),
126
+ };
127
+ }
128
+ function drainAtEntry() {
129
+ return drainOutboxAtEntry({
130
+ outboxDir: defaultOutboxDir(),
131
+ rateDir: defaultRateDir(),
132
+ deliverCodex: (threadId, content, busyTimeoutMs) => deliverToCodexThread(threadId, content, { busyTimeoutMs }),
133
+ err: (line) => process.stderr.write(`${line}\n`),
134
+ });
135
+ }
136
+ function printFailure(err) {
137
+ const me = err instanceof MultichatError
138
+ ? err
139
+ : new MultichatError('INTERNAL', err instanceof Error ? err.message : String(err), { cause: err });
140
+ process.stderr.write(`crosschat: ${me.code}: ${me.message}\n`);
141
+ return 1;
142
+ }
143
+ /**
144
+ * Opportunistic outbox drain at command entry (send/status only): re-deliver
145
+ * parked messages with a short busy wait under the B11 round budget, one
146
+ * stderr line per thread that got relief, and one dead-letter line for a
147
+ * thread that no longer exists; silent when nothing was parked or nothing
148
+ * went through. Drain failures never fail the invoking command.
149
+ */
150
+ export async function drainOutboxAtEntry(deps) {
151
+ let results;
152
+ try {
153
+ results = await drain(deps.outboxDir, (threadId, content, busyTimeoutMs) => deps.deliverCodex(threadId, content, busyTimeoutMs), { rateDir: deps.rateDir });
154
+ }
155
+ catch {
156
+ return; // opportunistic: the real command still runs
157
+ }
158
+ for (const result of results) {
159
+ if (result.delivered > 0)
160
+ deps.err(`outbox: 补投 ${result.delivered} 条给 ${result.toName}`);
161
+ if (result.dropped > 0) {
162
+ deps.err(`outbox: 线程 ${result.threadId} 已不存在,丢弃 ${result.dropped} 条暂存消息`);
163
+ }
164
+ }
165
+ }
166
+ async function main(argv) {
167
+ const [command, ...rest] = argv;
168
+ if (command === undefined || command === '') {
169
+ process.stderr.write(usage);
170
+ return 1;
171
+ }
172
+ if (command === '--version' || command === '-v') {
173
+ process.stdout.write(`${version}\n`);
174
+ return 0;
175
+ }
176
+ if (command === 'help' || command === '--help') {
177
+ process.stdout.write(usage);
178
+ return 0;
179
+ }
180
+ if (command === 'send') {
181
+ if (rest.includes('--help')) {
182
+ process.stdout.write(usage);
183
+ return 0;
184
+ }
185
+ try {
186
+ const args = parseSendArgs(rest);
187
+ await drainAtEntry();
188
+ // Only read stdin when --body is absent: agent harnesses often leave the
189
+ // stdin pipe open forever, and blocking on it with --body given would hang.
190
+ const stdinText = args.bodyArg === undefined ? await readStdinText() : undefined;
191
+ const output = await runSend(args, realSendDeps(stdinText));
192
+ process.stdout.write(`${output}\n`);
193
+ return 0;
194
+ }
195
+ catch (err) {
196
+ return printFailure(err);
197
+ }
198
+ }
199
+ if (command === 'status') {
200
+ if (rest.includes('--help')) {
201
+ process.stdout.write(usage);
202
+ return 0;
203
+ }
204
+ try {
205
+ const { json } = parseStatusArgs(rest);
206
+ await drainAtEntry();
207
+ const output = await runStatus(realStatusDeps(), json);
208
+ process.stdout.write(`${output}\n`);
209
+ return 0;
210
+ }
211
+ catch (err) {
212
+ return printFailure(err);
213
+ }
214
+ }
215
+ if (command === 'doctor') {
216
+ if (rest.includes('--help')) {
217
+ process.stdout.write(usage);
218
+ return 0;
219
+ }
220
+ if (rest.length > 0) {
221
+ process.stderr.write(`crosschat: USAGE: doctor takes no options; got: ${rest.join(' ')}\n\n`);
222
+ process.stderr.write(usage);
223
+ return 1;
224
+ }
225
+ const report = runDoctor();
226
+ process.stdout.write(`${report.output}\n`);
227
+ return report.failed ? 1 : 0;
228
+ }
229
+ if (command === 'install-skills') {
230
+ if (rest.includes('--help')) {
231
+ process.stdout.write(usage);
232
+ return 0;
233
+ }
234
+ try {
235
+ const args = parseInstallSkillsArgs(rest);
236
+ for (const path of runInstallSkills(args))
237
+ process.stdout.write(`installed: ${path}\n`);
238
+ return 0;
239
+ }
240
+ catch (err) {
241
+ return printFailure(err);
242
+ }
243
+ }
244
+ if (command === 'claude') {
245
+ // Everything passes through to the real claude CLI (including --help).
246
+ try {
247
+ return await runClaudeWrapper(rest);
248
+ }
249
+ catch (err) {
250
+ return printFailure(err);
251
+ }
252
+ }
253
+ process.stderr.write(`crosschat: USAGE: unknown command: ${command}\n\n`);
254
+ process.stderr.write(usage);
255
+ return 1;
256
+ }
257
+ function isDirectRun() {
258
+ try {
259
+ return realpathSync(process.argv[1] ?? '') === realpathSync(fileURLToPath(import.meta.url));
260
+ }
261
+ catch {
262
+ return false;
263
+ }
264
+ }
265
+ if (isDirectRun()) {
266
+ void main(process.argv.slice(2)).then((code) => {
267
+ process.exitCode = code;
268
+ });
269
+ }
270
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,130 @@
1
+ import { MultichatError } from '../errors.js';
2
+ import { CodexRpcClient } from './rpc.js';
3
+ import { openCodexProxySession, } from './transport.js';
4
+ function isRecord(value) {
5
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
6
+ }
7
+ function protocolError(message) {
8
+ return new MultichatError('CODEX_PROTOCOL_ERROR', message);
9
+ }
10
+ export function normalizeThreadStatus(value) {
11
+ if (!isRecord(value) || typeof value.type !== 'string') {
12
+ throw protocolError('codex thread.status missing or malformed.');
13
+ }
14
+ switch (value.type) {
15
+ case 'notLoaded':
16
+ return 'not_loaded';
17
+ case 'idle':
18
+ return 'idle';
19
+ case 'systemError':
20
+ return 'system_error';
21
+ case 'active': {
22
+ const flags = Array.isArray(value.activeFlags) ? value.activeFlags : [];
23
+ // waitingOnUserInput is treated like an approval: only the user may answer.
24
+ return flags.includes('waitingOnApproval') || flags.includes('waitingOnUserInput')
25
+ ? 'waiting_approval'
26
+ : 'busy';
27
+ }
28
+ default:
29
+ throw protocolError(`unknown codex thread status type: ${value.type}`);
30
+ }
31
+ }
32
+ /**
33
+ * Build a session factory. Each call performs the full fresh operation setup
34
+ * (spawn proxy -> WebSocket upgrade -> JSON-RPC client); the caller owns
35
+ * close(). One session per operation; no pooling, no reuse.
36
+ */
37
+ export function openCodexSession(options = {}) {
38
+ return async () => {
39
+ const proxy = await openCodexProxySession(options);
40
+ const rpc = new CodexRpcClient(proxy.channel, options.requestTimeoutMs);
41
+ const input = (text) => [{ text, type: 'text' }];
42
+ const session = {
43
+ async initialize() {
44
+ await rpc.request('initialize', {
45
+ capabilities: { experimentalApi: true },
46
+ clientInfo: { name: 'crosschat', title: 'crosschat', version: '1.0.0' },
47
+ });
48
+ rpc.notify('initialized', {});
49
+ },
50
+ async listThreads() {
51
+ const result = await rpc.request('thread/list', {
52
+ archived: false,
53
+ limit: 20,
54
+ sortKey: 'recency_at',
55
+ useStateDbOnly: true,
56
+ });
57
+ if (!isRecord(result) || !Array.isArray(result.data)) {
58
+ throw protocolError('thread/list response missing data array.');
59
+ }
60
+ return result.data.map((raw) => {
61
+ if (!isRecord(raw) || typeof raw.id !== 'string') {
62
+ throw protocolError('thread/list item missing id.');
63
+ }
64
+ return {
65
+ id: raw.id,
66
+ name: typeof raw.name === 'string' ? raw.name : null,
67
+ status: normalizeThreadStatus(raw.status),
68
+ };
69
+ });
70
+ },
71
+ async resumeThread(threadId) {
72
+ const result = await rpc.request('thread/resume', {
73
+ excludeTurns: true,
74
+ threadId,
75
+ });
76
+ if (!isRecord(result) || !isRecord(result.thread) || result.thread.id !== threadId) {
77
+ throw protocolError('thread/resume response missing matching thread.');
78
+ }
79
+ return normalizeThreadStatus(result.thread.status);
80
+ },
81
+ async startTurn(threadId, text) {
82
+ const result = await rpc.request('turn/start', {
83
+ input: input(text),
84
+ threadId,
85
+ turnTrigger: 'crosschat',
86
+ });
87
+ if (!isRecord(result) ||
88
+ !isRecord(result.turn) ||
89
+ typeof result.turn.id !== 'string' ||
90
+ typeof result.turn.status !== 'string') {
91
+ throw protocolError('turn/start response missing turn.');
92
+ }
93
+ return { id: result.turn.id, status: result.turn.status };
94
+ },
95
+ async steerTurn(threadId, expectedTurnId, text) {
96
+ const result = await rpc.request('turn/steer', {
97
+ expectedTurnId,
98
+ input: input(text),
99
+ threadId,
100
+ });
101
+ if (!isRecord(result) || typeof result.turnId !== 'string') {
102
+ throw protocolError('turn/steer response missing turnId.');
103
+ }
104
+ return result.turnId;
105
+ },
106
+ async unsubscribe(threadId) {
107
+ await rpc.request('thread/unsubscribe', { threadId });
108
+ },
109
+ async startThread(cwd) {
110
+ const result = await rpc.request('thread/start', { cwd });
111
+ if (!isRecord(result) || !isRecord(result.thread) || typeof result.thread.id !== 'string') {
112
+ throw protocolError('thread/start response missing thread id.');
113
+ }
114
+ return result.thread.id;
115
+ },
116
+ async deleteThread(threadId) {
117
+ await rpc.request('thread/delete', { threadId });
118
+ },
119
+ notifications() {
120
+ return rpc.notifications;
121
+ },
122
+ async close() {
123
+ rpc.dispose();
124
+ await proxy.close();
125
+ },
126
+ };
127
+ return session;
128
+ };
129
+ }
130
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/codex/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,cAAc,EAA6B,MAAM,UAAU,CAAC;AACrE,OAAO,EACL,qBAAqB,GAGtB,MAAM,gBAAgB,CAAC;AAiDxB,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,SAAS,aAAa,CAAC,OAAe;IACpC,OAAO,IAAI,cAAc,CAAC,sBAAsB,EAAE,OAAO,CAAC,CAAC;AAC7D,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,KAAc;IAClD,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QACvD,MAAM,aAAa,CAAC,2CAA2C,CAAC,CAAC;IACnE,CAAC;IACD,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,WAAW;YACd,OAAO,YAAY,CAAC;QACtB,KAAK,MAAM;YACT,OAAO,MAAM,CAAC;QAChB,KAAK,aAAa;YAChB,OAAO,cAAc,CAAC;QACxB,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC;YACxE,4EAA4E;YAC5E,OAAO,KAAK,CAAC,QAAQ,CAAC,mBAAmB,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,oBAAoB,CAAC;gBAChF,CAAC,CAAC,kBAAkB;gBACpB,CAAC,CAAC,MAAM,CAAC;QACb,CAAC;QACD;YACE,MAAM,aAAa,CAAC,qCAAqC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IAC3E,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,UAA+B,EAAE;IAChE,OAAO,KAAK,IAAI,EAAE;QAChB,MAAM,KAAK,GAAG,MAAM,qBAAqB,CAAC,OAAO,CAAC,CAAC;QACnD,MAAM,GAAG,GAAG,IAAI,cAAc,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC;QACxE,MAAM,KAAK,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;QACzD,MAAM,OAAO,GAAiB;YAC5B,KAAK,CAAC,UAAU;gBACd,MAAM,GAAG,CAAC,OAAO,CAAC,YAAY,EAAE;oBAC9B,YAAY,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE;oBACvC,UAAU,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,EAAE;iBACxE,CAAC,CAAC;gBACH,GAAG,CAAC,MAAM,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;YAChC,CAAC;YACD,KAAK,CAAC,WAAW;gBACf,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,aAAa,EAAE;oBAC9C,QAAQ,EAAE,KAAK;oBACf,KAAK,EAAE,EAAE;oBACT,OAAO,EAAE,YAAY;oBACrB,cAAc,EAAE,IAAI;iBACrB,CAAC,CAAC;gBACH,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;oBACrD,MAAM,aAAa,CAAC,0CAA0C,CAAC,CAAC;gBAClE,CAAC;gBACD,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;oBAC7B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,OAAO,GAAG,CAAC,EAAE,KAAK,QAAQ,EAAE,CAAC;wBACjD,MAAM,aAAa,CAAC,8BAA8B,CAAC,CAAC;oBACtD,CAAC;oBACD,OAAO;wBACL,EAAE,EAAE,GAAG,CAAC,EAAE;wBACV,IAAI,EAAE,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI;wBACpD,MAAM,EAAE,qBAAqB,CAAC,GAAG,CAAC,MAAM,CAAC;qBAC1C,CAAC;gBACJ,CAAC,CAAC,CAAC;YACL,CAAC;YACD,KAAK,CAAC,YAAY,CAAC,QAAgB;gBACjC,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,eAAe,EAAE;oBAChD,YAAY,EAAE,IAAI;oBAClB,QAAQ;iBACT,CAAC,CAAC;gBACH,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,QAAQ,EAAE,CAAC;oBACnF,MAAM,aAAa,CAAC,iDAAiD,CAAC,CAAC;gBACzE,CAAC;gBACD,OAAO,qBAAqB,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACrD,CAAC;YACD,KAAK,CAAC,SAAS,CAAC,QAAgB,EAAE,IAAY;gBAC5C,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,YAAY,EAAE;oBAC7C,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC;oBAClB,QAAQ;oBACR,WAAW,EAAE,WAAW;iBACzB,CAAC,CAAC;gBACH,IACE,CAAC,QAAQ,CAAC,MAAM,CAAC;oBACjB,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC;oBACtB,OAAO,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,QAAQ;oBAClC,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,KAAK,QAAQ,EACtC,CAAC;oBACD,MAAM,aAAa,CAAC,mCAAmC,CAAC,CAAC;gBAC3D,CAAC;gBACD,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YAC5D,CAAC;YACD,KAAK,CAAC,SAAS,CAAC,QAAgB,EAAE,cAAsB,EAAE,IAAY;gBACpE,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,YAAY,EAAE;oBAC7C,cAAc;oBACd,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC;oBAClB,QAAQ;iBACT,CAAC,CAAC;gBACH,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;oBAC3D,MAAM,aAAa,CAAC,qCAAqC,CAAC,CAAC;gBAC7D,CAAC;gBACD,OAAO,MAAM,CAAC,MAAM,CAAC;YACvB,CAAC;YACD,KAAK,CAAC,WAAW,CAAC,QAAgB;gBAChC,MAAM,GAAG,CAAC,OAAO,CAAC,oBAAoB,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;YACxD,CAAC;YACD,KAAK,CAAC,WAAW,CAAC,GAAW;gBAC3B,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;gBAC1D,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,OAAO,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,QAAQ,EAAE,CAAC;oBAC1F,MAAM,aAAa,CAAC,0CAA0C,CAAC,CAAC;gBAClE,CAAC;gBACD,OAAO,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1B,CAAC;YACD,KAAK,CAAC,YAAY,CAAC,QAAgB;gBACjC,MAAM,GAAG,CAAC,OAAO,CAAC,eAAe,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;YACnD,CAAC;YACD,aAAa;gBACX,OAAO,GAAG,CAAC,aAAa,CAAC;YAC3B,CAAC;YACD,KAAK,CAAC,KAAK;gBACT,GAAG,CAAC,OAAO,EAAE,CAAC;gBACd,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC;YACtB,CAAC;SACF,CAAC;QACF,OAAO,OAAO,CAAC;IACjB,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,162 @@
1
+ import { MultichatError } from '../errors.js';
2
+ import { openCodexSession, } from './client.js';
3
+ import { CodexRpcRejectedError } from './rpc.js';
4
+ const DEFAULT_BUSY_TIMEOUT_MS = 120_000;
5
+ const DEFAULT_POLL_INTERVAL_MS = 3_000;
6
+ /** Server-side rejection text when a codex TUI window holds the thread writer. */
7
+ const ACTIVE_WRITER_PATTERN = /already has an active writer/i;
8
+ /**
9
+ * Server-side rejection texts when the thread does not exist (deleted or
10
+ * archived); same evidence embassy's codex transport classifies as not_found.
11
+ */
12
+ const THREAD_NOT_FOUND_PATTERN = /^(thread not found: |no rollout found for thread id |session .+ is archived\.)/i;
13
+ const OS_ERROR_PATTERN = /os error \d+/gi;
14
+ const STDERR_EXCERPT_CHARS = 300;
15
+ const DAEMON_START_HINT = 'codex app-server daemon 可能未启动,可运行: codex app-server daemon start';
16
+ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
17
+ export async function deliverToCodexThread(threadId, content, options = {}) {
18
+ const busyTimeoutMs = options.busyTimeoutMs ?? DEFAULT_BUSY_TIMEOUT_MS;
19
+ const pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
20
+ const sessionFactory = options.sessionFactory ?? openCodexSession();
21
+ let session;
22
+ try {
23
+ session = await sessionFactory();
24
+ }
25
+ catch (err) {
26
+ throw spawnFailure(err);
27
+ }
28
+ let resumed = false;
29
+ try {
30
+ try {
31
+ await session.initialize();
32
+ const deadline = Date.now() + busyTimeoutMs;
33
+ // Disposition loop: idle -> proceed; busy or TUI active-writer -> poll
34
+ // for release (both release into the same headless delivery);
35
+ // waiting_approval -> APPROVAL_REQUIRED (never answered for the user);
36
+ // system_error -> fail; not_loaded keeps polling (the server loads
37
+ // asynchronously after resume).
38
+ let writerHeld = false;
39
+ for (;;) {
40
+ let status;
41
+ try {
42
+ status = await session.resumeThread(threadId);
43
+ }
44
+ catch (err) {
45
+ // A codex TUI window holds the thread writer, so the server rejects
46
+ // resume. `codex queue` is NOT a fallback: it exits 0 but the
47
+ // message never reaches the local TUI (measured black hole; the
48
+ // feature looks remote-architecture only). Instead, wait for the
49
+ // window to release the writer, then deliver headless.
50
+ if (err instanceof CodexRpcRejectedError && ACTIVE_WRITER_PATTERN.test(err.message)) {
51
+ writerHeld = true;
52
+ }
53
+ else if (err instanceof CodexRpcRejectedError &&
54
+ THREAD_NOT_FOUND_PATTERN.test(err.message)) {
55
+ throw new MultichatError('CODEX_THREAD_NOT_FOUND', `Codex thread ${threadId} 不存在(可能已删除),无法投递。`, { cause: err });
56
+ }
57
+ else {
58
+ throw err;
59
+ }
60
+ }
61
+ if (status !== undefined) {
62
+ resumed = true;
63
+ if (status === 'idle')
64
+ break;
65
+ if (status === 'waiting_approval') {
66
+ throw new MultichatError('CODEX_APPROVAL_REQUIRED', `Codex thread ${threadId} is waiting for an approval; only the user can answer it.`);
67
+ }
68
+ if (status === 'system_error') {
69
+ throw protocolFailure(`Codex thread ${threadId} is in system_error state.`, undefined);
70
+ }
71
+ // Resume succeeded, so no writer lock; the thread is merely busy.
72
+ writerHeld = false;
73
+ }
74
+ if (Date.now() + pollIntervalMs > deadline) {
75
+ if (writerHeld) {
76
+ throw new MultichatError('CODEX_THREAD_LOCKED', `Codex thread ${threadId} 正被 codex 窗口占用,等待 ${busyTimeoutMs / 1000}s 未释放。` +
77
+ '关闭该窗口后重发将立即送达;或改投其它线程。');
78
+ }
79
+ throw new MultichatError('CODEX_THREAD_BUSY_TIMEOUT', `Codex thread ${threadId} stayed busy longer than ${busyTimeoutMs}ms.`);
80
+ }
81
+ await sleep(pollIntervalMs);
82
+ }
83
+ }
84
+ catch (err) {
85
+ if (err instanceof MultichatError &&
86
+ (err.code === 'CODEX_APPROVAL_REQUIRED' ||
87
+ err.code === 'CODEX_THREAD_BUSY_TIMEOUT' ||
88
+ err.code === 'CODEX_THREAD_LOCKED' ||
89
+ err.code === 'CODEX_THREAD_NOT_FOUND')) {
90
+ throw err;
91
+ }
92
+ // Pre-write failures (timeout, transport closed, rpc rejection, bad
93
+ // frames) all collapse to CODEX_PROTOCOL_ERROR: nothing was written.
94
+ const detail = err instanceof Error ? ` (${err.message})` : '';
95
+ throw protocolFailure(`codex setup (initialize/resume) failed for ${threadId}.${detail}`, err);
96
+ }
97
+ let turn;
98
+ try {
99
+ turn = await session.startTurn(threadId, content);
100
+ }
101
+ catch (err) {
102
+ if (err instanceof CodexRpcRejectedError) {
103
+ throw new MultichatError('CODEX_TURN_REJECTED', `Codex rejected the turn for thread ${threadId}: ${err.message}`, { cause: err });
104
+ }
105
+ // Timeout/transport/protocol after the write was sent: acceptance is
106
+ // unknown, and we never resend.
107
+ throw new MultichatError('CODEX_WRITE_UNCERTAIN', `Acceptance of the turn for thread ${threadId} could not be confirmed.`, { cause: err });
108
+ }
109
+ if (turn.status !== 'inProgress') {
110
+ throw new MultichatError('CODEX_WRITE_UNCERTAIN', `Turn for thread ${threadId} returned unexpected status: ${turn.status}.`);
111
+ }
112
+ return { status: 'accepted', turnId: turn.id };
113
+ }
114
+ finally {
115
+ if (resumed) {
116
+ await session.unsubscribe(threadId).catch(() => undefined);
117
+ }
118
+ await session.close().catch(() => undefined);
119
+ }
120
+ }
121
+ function protocolFailure(message, cause) {
122
+ return new MultichatError('CODEX_PROTOCOL_ERROR', message, { cause });
123
+ }
124
+ /**
125
+ * CODEX_PROXY_SPAWN_FAILED with the underlying evidence attached: the bounded
126
+ * stderr tail of the dead proxy (<=300 chars) and any os-error mentions from
127
+ * the cause chain (e.g. "os error 10061", daemon socket refused).
128
+ */
129
+ function spawnFailure(err) {
130
+ const base = err instanceof MultichatError && err.code === 'CODEX_PROXY_SPAWN_FAILED'
131
+ ? err.message
132
+ : 'Failed to establish the codex app-server proxy channel.';
133
+ const { stderrTail, osErrors } = proxyFailureEvidence(err);
134
+ const parts = [base];
135
+ if (osErrors.length > 0)
136
+ parts.push(`底层 OS 错误: ${osErrors.join(', ')}.`);
137
+ if (stderrTail !== '')
138
+ parts.push(`proxy stderr 尾部: ${stderrTail}`);
139
+ if (!base.includes('executable not found'))
140
+ parts.push(DAEMON_START_HINT);
141
+ return new MultichatError('CODEX_PROXY_SPAWN_FAILED', parts.join(' '), { cause: err });
142
+ }
143
+ function proxyFailureEvidence(err) {
144
+ const osErrors = new Set();
145
+ let stderrTail = '';
146
+ const seen = new Set();
147
+ let current = err;
148
+ while (current instanceof Error && !seen.has(current)) {
149
+ seen.add(current);
150
+ const text = current.stderrText;
151
+ if (stderrTail === '' && typeof text === 'string' && text !== '') {
152
+ stderrTail = text.replace(/\s+/g, ' ').trim().slice(-STDERR_EXCERPT_CHARS);
153
+ }
154
+ for (const match of current.message.matchAll(OS_ERROR_PATTERN))
155
+ osErrors.add(match[0]);
156
+ current = current.cause;
157
+ }
158
+ for (const match of stderrTail.matchAll(OS_ERROR_PATTERN))
159
+ osErrors.add(match[0]);
160
+ return { stderrTail, osErrors: [...osErrors] };
161
+ }
162
+ //# sourceMappingURL=deliver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deliver.js","sourceRoot":"","sources":["../../src/codex/deliver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ import { MultichatError } from '../errors.js';
2
+ import { openCodexSession } from './client.js';
3
+ import { codexHomeDir, lookupRolloutMetas } from './rollout-meta.js';
4
+ /**
5
+ * Read-only Codex thread discovery: initialize + thread/list on a fresh proxy
6
+ * session, then close. Never resumes, starts turns, or mutates anything.
7
+ * Each listed thread is tagged with its rollout session metadata (cwd,
8
+ * originator, creation time); a metadata lookup failure never fails the list.
9
+ */
10
+ export async function listCodexThreads(options = {}) {
11
+ const sessionFactory = options.sessionFactory ?? openCodexSession();
12
+ let session;
13
+ try {
14
+ session = await sessionFactory();
15
+ }
16
+ catch (err) {
17
+ if (err instanceof MultichatError && err.code === 'CODEX_PROXY_SPAWN_FAILED')
18
+ throw err;
19
+ throw new MultichatError('CODEX_PROXY_SPAWN_FAILED', 'Failed to establish the codex app-server proxy channel.', { cause: err });
20
+ }
21
+ try {
22
+ await session.initialize();
23
+ const threads = await session.listThreads();
24
+ let metas = new Map();
25
+ try {
26
+ metas = lookupRolloutMetas(options.codexHome ?? codexHomeDir(), threads.map((t) => t.id));
27
+ }
28
+ catch {
29
+ // Metadata is best-effort identification only.
30
+ }
31
+ return threads.map((thread) => {
32
+ const meta = metas.get(thread.id);
33
+ return meta === undefined ? thread : { ...thread, meta };
34
+ });
35
+ }
36
+ catch (err) {
37
+ if (err instanceof MultichatError)
38
+ throw err;
39
+ throw new MultichatError('CODEX_PROTOCOL_ERROR', 'codex thread/list failed.', { cause: err });
40
+ }
41
+ finally {
42
+ await session.close().catch(() => undefined);
43
+ }
44
+ }
45
+ //# sourceMappingURL=discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../src/codex/discovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAqD,MAAM,aAAa,CAAC;AAClG,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAoB,MAAM,mBAAmB,CAAC;AAQvF;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,UAAwE,EAAE;IAE1E,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,IAAI,gBAAgB,EAAE,CAAC;IACpE,IAAI,OAAO,CAAC;IACZ,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,cAAc,EAAE,CAAC;IACnC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,cAAc,IAAI,GAAG,CAAC,IAAI,KAAK,0BAA0B;YAAE,MAAM,GAAG,CAAC;QACxF,MAAM,IAAI,cAAc,CACtB,0BAA0B,EAC1B,yDAAyD,EACzD,EAAE,KAAK,EAAE,GAAG,EAAE,CACf,CAAC;IACJ,CAAC;IACD,IAAI,CAAC;QACH,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,WAAW,EAAE,CAAC;QAC5C,IAAI,KAAK,GAAG,IAAI,GAAG,EAAuB,CAAC;QAC3C,IAAI,CAAC;YACH,KAAK,GAAG,kBAAkB,CAAC,OAAO,CAAC,SAAS,IAAI,YAAY,EAAE,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC5F,CAAC;QAAC,MAAM,CAAC;YACP,+CAA+C;QACjD,CAAC;QACD,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;YAC5B,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAClC,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,EAAE,IAAI,EAAE,CAAC;QAC3D,CAAC,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,cAAc;YAAE,MAAM,GAAG,CAAC;QAC7C,MAAM,IAAI,cAAc,CAAC,sBAAsB,EAAE,2BAA2B,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;IAChG,CAAC;YAAS,CAAC;QACT,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;IAC/C,CAAC;AACH,CAAC"}