echo-cli-agent 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.
Files changed (82) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +38 -0
  3. package/dist/src/config.d.ts +33 -0
  4. package/dist/src/config.js +154 -0
  5. package/dist/src/config.js.map +1 -0
  6. package/dist/src/dispatch/dispatcher.d.ts +34 -0
  7. package/dist/src/dispatch/dispatcher.js +216 -0
  8. package/dist/src/dispatch/dispatcher.js.map +1 -0
  9. package/dist/src/health/server.d.ts +25 -0
  10. package/dist/src/health/server.js +122 -0
  11. package/dist/src/health/server.js.map +1 -0
  12. package/dist/src/index.d.ts +2 -0
  13. package/dist/src/index.js +82 -0
  14. package/dist/src/index.js.map +1 -0
  15. package/dist/src/logging/diagnostic-log.d.ts +15 -0
  16. package/dist/src/logging/diagnostic-log.js +92 -0
  17. package/dist/src/logging/diagnostic-log.js.map +1 -0
  18. package/dist/src/providers/claude.d.ts +2 -0
  19. package/dist/src/providers/claude.js +20 -0
  20. package/dist/src/providers/claude.js.map +1 -0
  21. package/dist/src/providers/codex.d.ts +2 -0
  22. package/dist/src/providers/codex.js +39 -0
  23. package/dist/src/providers/codex.js.map +1 -0
  24. package/dist/src/providers/kiro.d.ts +2 -0
  25. package/dist/src/providers/kiro.js +33 -0
  26. package/dist/src/providers/kiro.js.map +1 -0
  27. package/dist/src/providers/model-catalog.d.ts +16 -0
  28. package/dist/src/providers/model-catalog.js +156 -0
  29. package/dist/src/providers/model-catalog.js.map +1 -0
  30. package/dist/src/providers/provider.d.ts +32 -0
  31. package/dist/src/providers/provider.js +57 -0
  32. package/dist/src/providers/provider.js.map +1 -0
  33. package/dist/src/providers/registry.d.ts +9 -0
  34. package/dist/src/providers/registry.js +44 -0
  35. package/dist/src/providers/registry.js.map +1 -0
  36. package/dist/src/runtime/agent-runtime.d.ts +13 -0
  37. package/dist/src/runtime/agent-runtime.js +55 -0
  38. package/dist/src/runtime/agent-runtime.js.map +1 -0
  39. package/dist/src/runtime/cli/hydrate-shell-path.d.ts +33 -0
  40. package/dist/src/runtime/cli/hydrate-shell-path.js +173 -0
  41. package/dist/src/runtime/cli/hydrate-shell-path.js.map +1 -0
  42. package/dist/src/session/final-output.d.ts +1 -0
  43. package/dist/src/session/final-output.js +16 -0
  44. package/dist/src/session/final-output.js.map +1 -0
  45. package/dist/src/session/session-manager.d.ts +42 -0
  46. package/dist/src/session/session-manager.js +339 -0
  47. package/dist/src/session/session-manager.js.map +1 -0
  48. package/dist/src/shared/node-cli-command-resolution.d.ts +11 -0
  49. package/dist/src/shared/node-cli-command-resolution.js +163 -0
  50. package/dist/src/shared/node-cli-command-resolution.js.map +1 -0
  51. package/dist/src/state/state-store.d.ts +48 -0
  52. package/dist/src/state/state-store.js +125 -0
  53. package/dist/src/state/state-store.js.map +1 -0
  54. package/dist/src/transport/taskmcp-client.d.ts +29 -0
  55. package/dist/src/transport/taskmcp-client.js +115 -0
  56. package/dist/src/transport/taskmcp-client.js.map +1 -0
  57. package/dist/src/types/protocol.d.ts +98 -0
  58. package/dist/src/types/protocol.js +38 -0
  59. package/dist/src/types/protocol.js.map +1 -0
  60. package/dist/tests/dispatch-integration.test.d.ts +1 -0
  61. package/dist/tests/dispatch-integration.test.js +209 -0
  62. package/dist/tests/dispatch-integration.test.js.map +1 -0
  63. package/dist/tests/final-output.test.d.ts +1 -0
  64. package/dist/tests/final-output.test.js +9 -0
  65. package/dist/tests/final-output.test.js.map +1 -0
  66. package/dist/tests/health-server.test.d.ts +1 -0
  67. package/dist/tests/health-server.test.js +38 -0
  68. package/dist/tests/health-server.test.js.map +1 -0
  69. package/dist/tests/model-catalog.test.d.ts +1 -0
  70. package/dist/tests/model-catalog.test.js +59 -0
  71. package/dist/tests/model-catalog.test.js.map +1 -0
  72. package/dist/tests/providers.test.d.ts +1 -0
  73. package/dist/tests/providers.test.js +95 -0
  74. package/dist/tests/providers.test.js.map +1 -0
  75. package/dist/tests/state-store.test.d.ts +1 -0
  76. package/dist/tests/state-store.test.js +22 -0
  77. package/dist/tests/state-store.test.js.map +1 -0
  78. package/dist/vitest.config.d.ts +2 -0
  79. package/dist/vitest.config.js +11 -0
  80. package/dist/vitest.config.js.map +1 -0
  81. package/package.json +42 -0
  82. package/scripts/service.mjs +158 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 api_ocra contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,38 @@
1
+ # echo-cli-agent
2
+
3
+ Local CLI bridge agent. Connects coding CLI tools (Codex, Claude Code, Kiro) to your workspace.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install -g echo-cli-agent
9
+ ```
10
+
11
+ Requires Node.js ≥ 20.
12
+
13
+ ## Usage
14
+
15
+ ```bash
16
+ # Check local environment
17
+ echo-cli-agent doctor
18
+
19
+ # Register this device
20
+ echo-cli-agent enroll --server <server-url> --code <pairing-code>
21
+
22
+ # Start the agent
23
+ echo-cli-agent run
24
+ ```
25
+
26
+ ## System Service
27
+
28
+ ```bash
29
+ # Register as a background service (launchd on macOS, systemd on Linux)
30
+ echo-cli-agent service:install
31
+
32
+ # Remove the service
33
+ echo-cli-agent service:uninstall
34
+ ```
35
+
36
+ ## License
37
+
38
+ MIT
@@ -0,0 +1,33 @@
1
+ import type { LogLevel } from './logging/diagnostic-log.js';
2
+ export type AgentConfig = {
3
+ wsUrl: string;
4
+ authMode: 'mcp' | 'bearer';
5
+ authToken: string;
6
+ deviceId: string;
7
+ deviceName: string;
8
+ endpoint: 'window' | 'cli';
9
+ capabilities: string[];
10
+ platform: NodeJS.Platform;
11
+ allowedRoots: string[];
12
+ allowExecutableOverride: boolean;
13
+ dataDir: string;
14
+ stateFile: string;
15
+ logFile: string;
16
+ healthHost: string;
17
+ healthPort: number;
18
+ logLevel: LogLevel;
19
+ };
20
+ export declare function defaultDataDir(): string;
21
+ export declare function defaultConfigPath(dataDir?: string): string;
22
+ export type EnrollmentOptions = {
23
+ serverUrl: string;
24
+ code: string;
25
+ deviceName?: string;
26
+ configPath?: string;
27
+ };
28
+ export declare function enrollDevice(options: EnrollmentOptions): Promise<{
29
+ deviceId: string;
30
+ configPath: string;
31
+ }>;
32
+ export declare function loadAgentConfig(): AgentConfig;
33
+ export declare function redactedConfig(config: AgentConfig): Record<string, unknown>;
@@ -0,0 +1,154 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { chmod, mkdir, readFile, rename, writeFile } from 'node:fs/promises';
3
+ import { homedir, hostname, platform } from 'node:os';
4
+ import { delimiter, dirname, join, resolve } from 'node:path';
5
+ import { z } from 'zod';
6
+ const FileConfigSchema = z
7
+ .object({
8
+ wsUrl: z.string().url().optional(),
9
+ authMode: z.enum(['mcp', 'bearer']).optional(),
10
+ authToken: z.string().min(1).optional(),
11
+ deviceId: z.string().min(1).optional(),
12
+ deviceName: z.string().min(1).optional(),
13
+ endpoint: z.enum(['window', 'cli']).optional(),
14
+ allowedRoots: z.array(z.string()).optional(),
15
+ allowExecutableOverride: z.boolean().optional(),
16
+ healthHost: z.string().optional(),
17
+ healthPort: z.number().int().min(0).max(65535).optional(),
18
+ logLevel: z.enum(['error', 'warn', 'info', 'debug']).optional()
19
+ })
20
+ .strict();
21
+ const EnrollResponseSchema = z.object({
22
+ device_id: z.string().min(1),
23
+ device_token: z.string().min(1),
24
+ ws_url: z.string().url(),
25
+ device_name: z.string().min(1)
26
+ });
27
+ export function defaultDataDir() {
28
+ if (process.platform === 'darwin') {
29
+ return join(homedir(), 'Library', 'Application Support', 'echo-cli-agent');
30
+ }
31
+ if (process.platform === 'win32') {
32
+ return join(process.env.APPDATA ?? homedir(), 'echo-cli-agent');
33
+ }
34
+ return join(process.env.XDG_STATE_HOME ?? join(homedir(), '.local', 'state'), 'echo-cli-agent');
35
+ }
36
+ export function defaultConfigPath(dataDir = resolve(process.env.ECHO_AGENT_DATA_DIR ?? defaultDataDir())) {
37
+ return resolve(process.env.ECHO_AGENT_CONFIG ?? join(dataDir, 'config.json'));
38
+ }
39
+ export async function enrollDevice(options) {
40
+ const endpoint = new URL('echo/device-enrollment/exchange', ensureTrailingSlash(options.serverUrl));
41
+ const response = await fetch(endpoint, {
42
+ method: 'POST',
43
+ headers: { 'content-type': 'application/json' },
44
+ body: JSON.stringify({
45
+ code: options.code,
46
+ ...(options.deviceName ? { device_name: options.deviceName } : {}),
47
+ platform: platform()
48
+ })
49
+ });
50
+ if (!response.ok)
51
+ throw new Error(`device enrollment failed (${response.status})`);
52
+ const enrolled = EnrollResponseSchema.parse(await response.json());
53
+ const dataDir = resolve(process.env.ECHO_AGENT_DATA_DIR ?? defaultDataDir());
54
+ const configPath = resolve(options.configPath ?? defaultConfigPath(dataDir));
55
+ await mkdir(dirname(configPath), { recursive: true, mode: 0o700 });
56
+ const existing = existsSync(configPath)
57
+ ? FileConfigSchema.parse(JSON.parse(await readFile(configPath, 'utf8')))
58
+ : {};
59
+ const serialized = JSON.stringify({
60
+ ...existing,
61
+ wsUrl: enrolled.ws_url,
62
+ authMode: 'mcp',
63
+ authToken: enrolled.device_token,
64
+ deviceId: enrolled.device_id,
65
+ deviceName: enrolled.device_name,
66
+ endpoint: 'cli'
67
+ }, null, 2);
68
+ const temporary = `${configPath}.${process.pid}.tmp`;
69
+ await writeFile(temporary, serialized, { mode: 0o600 });
70
+ await rename(temporary, configPath);
71
+ await chmod(configPath, 0o600);
72
+ return { deviceId: enrolled.device_id, configPath };
73
+ }
74
+ function ensureTrailingSlash(value) {
75
+ const url = new URL(value);
76
+ if (!url.pathname.endsWith('/'))
77
+ url.pathname += '/';
78
+ return url.toString();
79
+ }
80
+ function parseRoots(value) {
81
+ if (!value?.trim())
82
+ return undefined;
83
+ const separator = process.platform === 'win32' ? ';' : delimiter;
84
+ return value
85
+ .split(separator)
86
+ .map((item) => item.trim())
87
+ .filter(Boolean);
88
+ }
89
+ export function loadAgentConfig() {
90
+ const dataDir = resolve(process.env.ECHO_AGENT_DATA_DIR ?? defaultDataDir());
91
+ const configPath = defaultConfigPath(dataDir);
92
+ let fileConfig = {};
93
+ if (existsSync(configPath)) {
94
+ fileConfig = FileConfigSchema.parse(JSON.parse(readFileSync(configPath, 'utf8')));
95
+ }
96
+ const wsUrl = process.env.TASKMCP_WS_URL ?? fileConfig.wsUrl;
97
+ const authToken = process.env.TASKMCP_AUTH_TOKEN ?? fileConfig.authToken;
98
+ const deviceId = process.env.TASKMCP_DEVICE_ID ?? fileConfig.deviceId;
99
+ if (!wsUrl)
100
+ throw new Error('TASKMCP_WS_URL or config.wsUrl is required');
101
+ if (!authToken)
102
+ throw new Error('TASKMCP_AUTH_TOKEN or config.authToken is required');
103
+ if (!deviceId)
104
+ throw new Error('TASKMCP_DEVICE_ID is required from api_user route context');
105
+ const roots = parseRoots(process.env.TASKMCP_ALLOWED_ROOTS) ?? fileConfig.allowedRoots ?? [homedir()];
106
+ const healthPortText = process.env.ECHO_AGENT_HEALTH_PORT;
107
+ const healthPort = healthPortText ? Number.parseInt(healthPortText, 10) : (fileConfig.healthPort ?? 17329);
108
+ if (!Number.isInteger(healthPort) || healthPort < 0 || healthPort > 65535) {
109
+ throw new Error('ECHO_AGENT_HEALTH_PORT must be between 0 and 65535');
110
+ }
111
+ return {
112
+ wsUrl,
113
+ authMode: process.env.TASKMCP_AUTH_MODE ??
114
+ fileConfig.authMode ??
115
+ 'mcp',
116
+ authToken,
117
+ deviceId,
118
+ deviceName: process.env.TASKMCP_DEVICE_NAME ?? fileConfig.deviceName ?? hostname(),
119
+ endpoint: process.env.TASKMCP_ENDPOINT ?? fileConfig.endpoint ?? 'cli',
120
+ capabilities: (process.env.ECHO_AGENT_CAPABILITIES ?? '')
121
+ .split(',')
122
+ .map((value) => value.trim().toLowerCase())
123
+ .filter(Boolean),
124
+ platform: platform(),
125
+ allowedRoots: roots.map((root) => resolve(root)),
126
+ allowExecutableOverride: process.env.ECHO_AGENT_ALLOW_EXECUTABLE_OVERRIDE === 'true' ||
127
+ fileConfig.allowExecutableOverride === true,
128
+ dataDir,
129
+ stateFile: join(dataDir, 'state.json'),
130
+ logFile: join(dataDir, 'logs', 'agent.log'),
131
+ healthHost: process.env.ECHO_AGENT_HEALTH_HOST ?? fileConfig.healthHost ?? '127.0.0.1',
132
+ healthPort,
133
+ logLevel: process.env.ECHO_AGENT_LOG_LEVEL ?? fileConfig.logLevel ?? 'info'
134
+ };
135
+ }
136
+ export function redactedConfig(config) {
137
+ return {
138
+ wsUrl: config.wsUrl,
139
+ authMode: config.authMode,
140
+ authToken: '[redacted]',
141
+ deviceId: '[runtime-only]',
142
+ deviceName: config.deviceName,
143
+ endpoint: config.endpoint,
144
+ capabilities: config.capabilities,
145
+ platform: config.platform,
146
+ allowedRoots: config.allowedRoots,
147
+ allowExecutableOverride: config.allowExecutableOverride,
148
+ dataDir: config.dataDir,
149
+ healthHost: config.healthHost,
150
+ healthPort: config.healthPort,
151
+ logLevel: config.logLevel
152
+ };
153
+ }
154
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAClD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAC5E,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AACrD,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAC7D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,MAAM,gBAAgB,GAAG,CAAC;KACvB,MAAM,CAAC;IACN,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IAClC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE;IAC9C,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IACvC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IACtC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IACxC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,QAAQ,EAAE;IAC9C,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;IAC5C,uBAAuB,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAC/C,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACjC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE;IACzD,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAE;CAChE,CAAC;KACD,MAAM,EAAE,CAAA;AAEX,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IACpC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5B,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC/B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACxB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;CAC/B,CAAC,CAAA;AAqBF,MAAM,UAAU,cAAc;IAC5B,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAClC,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,qBAAqB,EAAE,gBAAgB,CAAC,CAAA;IAC5E,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,OAAO,EAAE,EAAE,gBAAgB,CAAC,CAAA;IACjE,CAAC;IACD,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,gBAAgB,CAAC,CAAA;AACjG,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,cAAc,EAAE,CAAC;IACtG,OAAO,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC,CAAA;AAC/E,CAAC;AASD,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,OAA0B;IAC3D,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,iCAAiC,EAAE,mBAAmB,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAA;IACnG,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,QAAQ,EAAE;QACrC,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;YACnB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAClE,QAAQ,EAAE,QAAQ,EAAE;SACrB,CAAC;KACH,CAAC,CAAA;IACF,IAAI,CAAC,QAAQ,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAA;IAClF,MAAM,QAAQ,GAAG,oBAAoB,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;IAClE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,cAAc,EAAE,CAAC,CAAA;IAC5E,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,UAAU,IAAI,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAA;IAC5E,MAAM,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;IAClE,MAAM,QAAQ,GAAG,UAAU,CAAC,UAAU,CAAC;QACrC,CAAC,CAAC,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC;QACxE,CAAC,CAAC,EAAE,CAAA;IACN,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC;QAChC,GAAG,QAAQ;QACX,KAAK,EAAE,QAAQ,CAAC,MAAM;QACtB,QAAQ,EAAE,KAAK;QACf,SAAS,EAAE,QAAQ,CAAC,YAAY;QAChC,QAAQ,EAAE,QAAQ,CAAC,SAAS;QAC5B,UAAU,EAAE,QAAQ,CAAC,WAAW;QAChC,QAAQ,EAAE,KAAK;KAChB,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;IACX,MAAM,SAAS,GAAG,GAAG,UAAU,IAAI,OAAO,CAAC,GAAG,MAAM,CAAA;IACpD,MAAM,SAAS,CAAC,SAAS,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;IACvD,MAAM,MAAM,CAAC,SAAS,EAAE,UAAU,CAAC,CAAA;IACnC,MAAM,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,CAAA;IAC9B,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,SAAS,EAAE,UAAU,EAAE,CAAA;AACrD,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAa;IACxC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAA;IAC1B,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAA;IACpD,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAA;AACvB,CAAC;AAED,SAAS,UAAU,CAAC,KAAyB;IAC3C,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE;QAAE,OAAO,SAAS,CAAA;IACpC,MAAM,SAAS,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAA;IAChE,OAAO,KAAK;SACT,KAAK,CAAC,SAAS,CAAC;SAChB,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SAC1B,MAAM,CAAC,OAAO,CAAC,CAAA;AACpB,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,cAAc,EAAE,CAAC,CAAA;IAC5E,MAAM,UAAU,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAA;IAC7C,IAAI,UAAU,GAAqC,EAAE,CAAA;IACrD,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC3B,UAAU,GAAG,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,CAAA;IACnF,CAAC;IAED,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,UAAU,CAAC,KAAK,CAAA;IAC5D,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,UAAU,CAAC,SAAS,CAAA;IACxE,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,UAAU,CAAC,QAAQ,CAAA;IACrE,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAA;IACzE,IAAI,CAAC,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAA;IACrF,IAAI,CAAC,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAA;IAE3F,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,IAAI,UAAU,CAAC,YAAY,IAAI,CAAC,OAAO,EAAE,CAAC,CAAA;IACrG,MAAM,cAAc,GAAG,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAA;IACzD,MAAM,UAAU,GAAG,cAAc,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,UAAU,IAAI,KAAK,CAAC,CAAA;IAC1G,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,UAAU,GAAG,CAAC,IAAI,UAAU,GAAG,KAAK,EAAE,CAAC;QAC1E,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAA;IACvE,CAAC;IAED,OAAO;QACL,KAAK;QACL,QAAQ,EACL,OAAO,CAAC,GAAG,CAAC,iBAAkD;YAC/D,UAAU,CAAC,QAAQ;YACnB,KAAK;QACP,SAAS;QACT,QAAQ;QACR,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,UAAU,CAAC,UAAU,IAAI,QAAQ,EAAE;QAClF,QAAQ,EAAG,OAAO,CAAC,GAAG,CAAC,gBAAiD,IAAI,UAAU,CAAC,QAAQ,IAAI,KAAK;QACxG,YAAY,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,uBAAuB,IAAI,EAAE,CAAC;aACtD,KAAK,CAAC,GAAG,CAAC;aACV,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;aAC1C,MAAM,CAAC,OAAO,CAAC;QAClB,QAAQ,EAAE,QAAQ,EAAE;QACpB,YAAY,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAChD,uBAAuB,EACrB,OAAO,CAAC,GAAG,CAAC,oCAAoC,KAAK,MAAM;YAC3D,UAAU,CAAC,uBAAuB,KAAK,IAAI;QAC7C,OAAO;QACP,SAAS,EAAE,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC;QACtC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC;QAC3C,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,UAAU,CAAC,UAAU,IAAI,WAAW;QACtF,UAAU;QACV,QAAQ,EACL,OAAO,CAAC,GAAG,CAAC,oBAA6C,IAAI,UAAU,CAAC,QAAQ,IAAI,MAAM;KAC9F,CAAA;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAmB;IAChD,OAAO;QACL,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,SAAS,EAAE,YAAY;QACvB,QAAQ,EAAE,gBAAgB;QAC1B,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,YAAY,EAAE,MAAM,CAAC,YAAY;QACjC,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,YAAY,EAAE,MAAM,CAAC,YAAY;QACjC,uBAAuB,EAAE,MAAM,CAAC,uBAAuB;QACvD,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,QAAQ,EAAE,MAAM,CAAC,QAAQ;KAC1B,CAAA;AACH,CAAC"}
@@ -0,0 +1,34 @@
1
+ import type { DiagnosticLogger } from '../logging/diagnostic-log.js';
2
+ import type { DeliveryHooks } from '../session/session-manager.js';
3
+ import type { CliWindowRecord, RunRecord, RunStatus } from '../state/state-store.js';
4
+ import { type AgentCliAck, type AgentCliControlAck, type AgentCliEvent, type AgentCliRequest, type DeliveryResult } from '../types/protocol.js';
5
+ export type SessionDelivery = {
6
+ deliver(request: AgentCliRequest, hooks: DeliveryHooks): Promise<DeliveryResult>;
7
+ cancelRun?(runId: string): boolean;
8
+ createWindow?(request: AgentCliRequest): Promise<CliWindowRecord>;
9
+ listWindows?(agentType?: string): CliWindowRecord[];
10
+ };
11
+ export type DeliveryState = {
12
+ getRun(runId: string): RunRecord | undefined;
13
+ markRun(runId: string, status: RunStatus, sessionId?: string): Promise<void>;
14
+ };
15
+ export type EventSender = {
16
+ sendEvent(event: AgentCliEvent): Promise<void>;
17
+ sendAck(ack: AgentCliAck): Promise<void>;
18
+ sendControlAck(ack: AgentCliControlAck): Promise<void>;
19
+ };
20
+ export declare class Dispatcher {
21
+ private readonly sessions;
22
+ private readonly state;
23
+ private readonly client;
24
+ private readonly logger;
25
+ private readonly queues;
26
+ constructor(sessions: SessionDelivery, state: DeliveryState, client: EventSender, logger: DiagnosticLogger);
27
+ accept(message: unknown): void;
28
+ waitForIdle(): Promise<void>;
29
+ private dispatch;
30
+ private control;
31
+ private completeRun;
32
+ private event;
33
+ private message;
34
+ }
@@ -0,0 +1,216 @@
1
+ import { AgentCliRequestSchema } from '../types/protocol.js';
2
+ import { readAgentModelCatalog } from '../providers/model-catalog.js';
3
+ export class Dispatcher {
4
+ sessions;
5
+ state;
6
+ client;
7
+ logger;
8
+ queues = new Map();
9
+ constructor(sessions, state, client, logger) {
10
+ this.sessions = sessions;
11
+ this.state = state;
12
+ this.client = client;
13
+ this.logger = logger;
14
+ }
15
+ accept(message) {
16
+ const parsed = AgentCliRequestSchema.safeParse(message);
17
+ if (!parsed.success)
18
+ return;
19
+ const request = parsed.data;
20
+ this.logger.info('agent-received', {
21
+ runId: request.run_id,
22
+ taskId: request.task_id,
23
+ agentType: request.agent_type
24
+ });
25
+ if (request.action !== 'prompt') {
26
+ void this.control(request);
27
+ return;
28
+ }
29
+ void this.event(request.run_id, 'agent_received', undefined, {}).catch((error) => {
30
+ this.logger.warn('agent-received-report-failed', {
31
+ runId: request.run_id,
32
+ error: this.message(error)
33
+ });
34
+ });
35
+ const queueKey = `${request.task_id}:${request.agent_type.toLowerCase()}`;
36
+ const previous = this.queues.get(queueKey) ?? Promise.resolve();
37
+ const next = previous
38
+ .then(() => this.dispatch(request))
39
+ .catch((error) => {
40
+ this.logger.error('dispatch-unhandled-error', { runId: request.run_id, error: this.message(error) });
41
+ })
42
+ .finally(() => {
43
+ if (this.queues.get(queueKey) === next)
44
+ this.queues.delete(queueKey);
45
+ });
46
+ this.queues.set(queueKey, next);
47
+ }
48
+ async waitForIdle() {
49
+ await Promise.all([...this.queues.values()]);
50
+ }
51
+ async dispatch(request) {
52
+ const previous = this.state.getRun(request.run_id);
53
+ if (previous?.status === 'completed') {
54
+ await this.event(request.run_id, 'prompt_delivered', previous.sessionId, { duplicate: true });
55
+ await this.event(request.run_id, 'completed', previous.sessionId, {
56
+ delivery: 'prompt_delivered',
57
+ duplicate: true
58
+ });
59
+ return;
60
+ }
61
+ await this.state.markRun(request.run_id, 'received');
62
+ try {
63
+ const result = await this.sessions.deliver(request, {
64
+ onProcessStarted: (sessionId, pid) => this.event(request.run_id, 'process_started', sessionId, { pid }),
65
+ onSessionInitialized: (sessionId, created) => this.event(request.run_id, 'session_initialized', sessionId, { created }),
66
+ onProcessExited: (sessionId, result) => this.completeRun(request, sessionId, result)
67
+ });
68
+ await this.state.markRun(request.run_id, 'delivered', result.sessionId);
69
+ await this.event(request.run_id, 'prompt_delivered', result.sessionId, {
70
+ delivered: true,
71
+ created: result.created
72
+ });
73
+ }
74
+ catch (error) {
75
+ await this.state.markRun(request.run_id, 'failed');
76
+ await this.event(request.run_id, 'failed', undefined, { message: this.message(error) }).catch(() => undefined);
77
+ this.logger.error('prompt-delivery-failed', {
78
+ runId: request.run_id,
79
+ agentType: request.agent_type,
80
+ error: this.message(error)
81
+ });
82
+ }
83
+ }
84
+ async control(request) {
85
+ try {
86
+ if (request.action === 'session_create') {
87
+ if (!this.sessions.createWindow)
88
+ throw new Error('当前 Agent 不支持创建窗口');
89
+ const window = await this.sessions.createWindow(request);
90
+ await this.client.sendControlAck({
91
+ type: 'agent_cli.control_ack',
92
+ run_id: request.run_id,
93
+ action: 'session_create',
94
+ status: 'done',
95
+ task_id: window.taskId,
96
+ agent_type: window.agentType,
97
+ name: window.name,
98
+ ...(window.providerSessionId ? { session_id: window.providerSessionId } : {})
99
+ });
100
+ return;
101
+ }
102
+ if (request.action === 'model_catalog') {
103
+ const agentType = request.agent_type.toLowerCase();
104
+ await this.client.sendControlAck({
105
+ type: 'agent_cli.control_ack',
106
+ run_id: request.run_id,
107
+ action: 'model_catalog',
108
+ status: 'done',
109
+ agent_type: agentType,
110
+ catalog: await readAgentModelCatalog(agentType)
111
+ });
112
+ return;
113
+ }
114
+ if (request.action === 'run_cancel') {
115
+ if (!this.sessions.cancelRun?.(request.run_id)) {
116
+ throw new Error('未找到可停止的本机 CLI 进程');
117
+ }
118
+ await this.client.sendControlAck({
119
+ type: 'agent_cli.control_ack',
120
+ run_id: request.run_id,
121
+ action: 'run_cancel',
122
+ status: 'done',
123
+ task_id: request.task_id,
124
+ agent_type: request.agent_type
125
+ });
126
+ return;
127
+ }
128
+ const windows = this.sessions.listWindows?.(request.agent_type) ?? [];
129
+ await this.client.sendControlAck({
130
+ type: 'agent_cli.control_ack',
131
+ run_id: request.run_id,
132
+ action: 'session_list',
133
+ status: 'done',
134
+ windows: windows.map((window) => ({
135
+ task_id: window.taskId,
136
+ agent_type: window.agentType,
137
+ name: window.name,
138
+ ...(window.providerSessionId ? { session_id: window.providerSessionId } : {})
139
+ }))
140
+ });
141
+ }
142
+ catch (error) {
143
+ const action = request.action === 'prompt' ? 'session_list' : request.action;
144
+ await this.client.sendControlAck({
145
+ type: 'agent_cli.control_ack',
146
+ run_id: request.run_id,
147
+ action,
148
+ status: 'failed',
149
+ ...(request.action === 'session_create'
150
+ ? { task_id: request.task_id, agent_type: request.agent_type }
151
+ : {}),
152
+ error: this.message(error)
153
+ }).catch(() => undefined);
154
+ this.logger.warn('cli-window-control-failed', {
155
+ runId: request.run_id,
156
+ action,
157
+ error: this.message(error)
158
+ });
159
+ }
160
+ }
161
+ async completeRun(request, sessionId, result) {
162
+ await this.event(request.run_id, 'process_exited', sessionId, {
163
+ exit_code: result.exitCode,
164
+ ...(result.signal ? { signal: result.signal } : {}),
165
+ duration_ms: result.durationMs
166
+ }).catch(() => undefined);
167
+ const status = result.cancelled ? 'cancelled' : (result.exitCode === 0 ? 'done' : 'failed');
168
+ const failureText = status === 'failed'
169
+ ? result.finalText?.trim().slice(0, 500) || `CLI exited with code ${result.exitCode}`
170
+ : undefined;
171
+ const ack = {
172
+ type: 'agent_cli.ack',
173
+ run_id: request.run_id,
174
+ ...(request.task_id ? { task_id: request.task_id } : {}),
175
+ ...(request.conversation_id ? { conversation_id: request.conversation_id } : {}),
176
+ ...(request.user_message_id ? { user_message_id: request.user_message_id } : {}),
177
+ agent_type: request.agent_type,
178
+ session_id: sessionId,
179
+ status,
180
+ exit_code: result.exitCode,
181
+ ...(failureText ? { stderr: failureText } : {}),
182
+ duration_ms: result.durationMs
183
+ };
184
+ try {
185
+ await this.client.sendAck(ack);
186
+ await this.state.markRun(request.run_id, status === 'done' ? 'completed' : 'failed', sessionId);
187
+ this.logger.info('cli-result-reported', {
188
+ runId: request.run_id,
189
+ agentType: request.agent_type,
190
+ status,
191
+ exitCode: result.exitCode,
192
+ durationMs: result.durationMs
193
+ });
194
+ }
195
+ catch (error) {
196
+ this.logger.warn('cli-result-report-failed', {
197
+ runId: request.run_id,
198
+ error: this.message(error)
199
+ });
200
+ }
201
+ }
202
+ event(runId, stage, sessionId, data) {
203
+ const event = {
204
+ type: 'agent_cli.event',
205
+ run_id: runId,
206
+ stage,
207
+ ...(sessionId ? { session_id: sessionId } : {}),
208
+ data
209
+ };
210
+ return this.client.sendEvent(event);
211
+ }
212
+ message(error) {
213
+ return error instanceof Error ? error.message : String(error);
214
+ }
215
+ }
216
+ //# sourceMappingURL=dispatcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatcher.js","sourceRoot":"","sources":["../../../src/dispatch/dispatcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import type { DiagnosticLogger } from '../logging/diagnostic-log.js';
2
+ import type { RunRecord } from '../state/state-store.js';
3
+ export type HealthSnapshot = {
4
+ deviceId: string;
5
+ connected: boolean;
6
+ activeSessions: number;
7
+ storedRuns: number;
8
+ startedAt: string;
9
+ runs: RunRecord[];
10
+ };
11
+ export declare class HealthServer {
12
+ private readonly host;
13
+ private readonly port;
14
+ private readonly snapshot;
15
+ private readonly logFile;
16
+ private readonly logger;
17
+ private server;
18
+ constructor(host: string, port: number, snapshot: () => HealthSnapshot, logFile: string, logger: DiagnosticLogger);
19
+ get boundPort(): number;
20
+ start(): Promise<void>;
21
+ stop(): Promise<void>;
22
+ private handle;
23
+ private json;
24
+ private recentEvents;
25
+ }