@router-agent/runtime 0.0.0-stage → 0.3.31

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 (124) hide show
  1. package/dist/agents/claude.d.ts +51 -0
  2. package/dist/agents/claude.js +270 -0
  3. package/dist/agents/claude.js.map +1 -0
  4. package/dist/agents/codex.d.ts +36 -0
  5. package/dist/agents/codex.js +292 -0
  6. package/dist/agents/codex.js.map +1 -0
  7. package/dist/agents/profile.d.ts +39 -0
  8. package/dist/agents/profile.js +2 -0
  9. package/dist/agents/profile.js.map +1 -0
  10. package/dist/agents/registry.d.ts +21 -0
  11. package/dist/agents/registry.js +78 -0
  12. package/dist/agents/registry.js.map +1 -0
  13. package/dist/errors.d.ts +4 -0
  14. package/dist/errors.js +9 -0
  15. package/dist/errors.js.map +1 -0
  16. package/dist/evidence-gate.d.ts +78 -0
  17. package/dist/evidence-gate.js +196 -0
  18. package/dist/evidence-gate.js.map +1 -0
  19. package/dist/index.d.ts +22 -0
  20. package/dist/index.js +21 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/naming.d.ts +23 -0
  23. package/dist/naming.js +40 -0
  24. package/dist/naming.js.map +1 -0
  25. package/dist/orca/commands.js +60 -0
  26. package/dist/orca/commands.js.map +1 -0
  27. package/dist/orca/index.js +452 -0
  28. package/dist/orca/index.js.map +1 -0
  29. package/dist/orca/options.js +33 -0
  30. package/dist/orca/options.js.map +1 -0
  31. package/dist/orca/report-poller.js +143 -0
  32. package/dist/orca/report-poller.js.map +1 -0
  33. package/dist/permissions/acp.d.ts +21 -0
  34. package/dist/permissions/acp.js +73 -0
  35. package/dist/permissions/acp.js.map +1 -0
  36. package/dist/permissions.d.ts +1 -0
  37. package/dist/permissions.js +2 -0
  38. package/dist/permissions.js.map +1 -0
  39. package/dist/plugins/loader.d.ts +46 -0
  40. package/dist/plugins/loader.js +117 -0
  41. package/dist/plugins/loader.js.map +1 -0
  42. package/dist/plugins/types.d.ts +52 -0
  43. package/dist/plugins/types.js +2 -0
  44. package/dist/plugins/types.js.map +1 -0
  45. package/dist/port.d.ts +295 -0
  46. package/dist/port.js +17 -0
  47. package/dist/port.js.map +1 -0
  48. package/dist/registry.d.ts +13 -0
  49. package/dist/registry.js +35 -0
  50. package/dist/registry.js.map +1 -0
  51. package/dist/report-poller.d.ts +58 -0
  52. package/dist/report-poller.js +130 -0
  53. package/dist/report-poller.js.map +1 -0
  54. package/dist/resume.d.ts +52 -0
  55. package/dist/resume.js +109 -0
  56. package/dist/resume.js.map +1 -0
  57. package/dist/runtimes/acp/admin.js +470 -0
  58. package/dist/runtimes/acp/admin.js.map +1 -0
  59. package/dist/runtimes/acp/agents.js +167 -0
  60. package/dist/runtimes/acp/agents.js.map +1 -0
  61. package/dist/runtimes/acp/detect.js +379 -0
  62. package/dist/runtimes/acp/detect.js.map +1 -0
  63. package/dist/runtimes/acp/index.js +633 -0
  64. package/dist/runtimes/acp/index.js.map +1 -0
  65. package/dist/runtimes/acp/install.js +264 -0
  66. package/dist/runtimes/acp/install.js.map +1 -0
  67. package/dist/runtimes/acp/permissions.js +83 -0
  68. package/dist/runtimes/acp/permissions.js.map +1 -0
  69. package/dist/runtimes/acp/protocol.js +207 -0
  70. package/dist/runtimes/acp/protocol.js.map +1 -0
  71. package/dist/runtimes/acp-agents.d.ts +85 -0
  72. package/dist/runtimes/acp-agents.js +167 -0
  73. package/dist/runtimes/acp-agents.js.map +1 -0
  74. package/dist/runtimes/acp-detect-utils.d.ts +4 -0
  75. package/dist/runtimes/acp-detect-utils.js +35 -0
  76. package/dist/runtimes/acp-detect-utils.js.map +1 -0
  77. package/dist/runtimes/builtin-options.d.ts +3 -0
  78. package/dist/runtimes/builtin-options.js +44 -0
  79. package/dist/runtimes/builtin-options.js.map +1 -0
  80. package/dist/runtimes/catalog.d.ts +31 -0
  81. package/dist/runtimes/catalog.js +75 -0
  82. package/dist/runtimes/catalog.js.map +1 -0
  83. package/dist/runtimes/claude-code/index.js +544 -0
  84. package/dist/runtimes/claude-code/index.js.map +1 -0
  85. package/dist/runtimes/claude-code/inject.js +71 -0
  86. package/dist/runtimes/claude-code/inject.js.map +1 -0
  87. package/dist/runtimes/codex/client.js +203 -0
  88. package/dist/runtimes/codex/client.js.map +1 -0
  89. package/dist/runtimes/codex/detect.js +240 -0
  90. package/dist/runtimes/codex/detect.js.map +1 -0
  91. package/dist/runtimes/codex/index.js +1066 -0
  92. package/dist/runtimes/codex/index.js.map +1 -0
  93. package/dist/runtimes/herdr/agents.js +38 -0
  94. package/dist/runtimes/herdr/agents.js.map +1 -0
  95. package/dist/runtimes/herdr/commands.js +68 -0
  96. package/dist/runtimes/herdr/commands.js.map +1 -0
  97. package/dist/runtimes/herdr/index.js +712 -0
  98. package/dist/runtimes/herdr/index.js.map +1 -0
  99. package/dist/runtimes/herdr/options.js +29 -0
  100. package/dist/runtimes/herdr/options.js.map +1 -0
  101. package/dist/runtimes/herdr/server.js +75 -0
  102. package/dist/runtimes/herdr/server.js.map +1 -0
  103. package/dist/runtimes/options.d.ts +60 -0
  104. package/dist/runtimes/options.js +89 -0
  105. package/dist/runtimes/options.js.map +1 -0
  106. package/dist/spec/contract.md +120 -0
  107. package/dist/spec/index.d.ts +35 -0
  108. package/dist/spec/index.js +59 -0
  109. package/dist/spec/index.js.map +1 -0
  110. package/dist/spec/prompt-mode.md +176 -0
  111. package/dist/spec/reader.d.ts +5 -0
  112. package/dist/spec/reader.js +32 -0
  113. package/dist/spec/reader.js.map +1 -0
  114. package/dist/status.d.ts +8 -0
  115. package/dist/status.js +22 -0
  116. package/dist/status.js.map +1 -0
  117. package/dist/workspaces/git-worktree.d.ts +44 -0
  118. package/dist/workspaces/git-worktree.js +183 -0
  119. package/dist/workspaces/git-worktree.js.map +1 -0
  120. package/dist/workspaces/overview.d.ts +66 -0
  121. package/dist/workspaces/overview.js +12 -0
  122. package/dist/workspaces/overview.js.map +1 -0
  123. package/package.json +36 -4
  124. package/README.md +0 -3
package/dist/port.d.ts ADDED
@@ -0,0 +1,295 @@
1
+ import type { Assignment, InputKind, Ticket } from '@router-agent/core/model.js';
2
+ /** 工单执行上下文:Router 负责拼装,运行时只消费。 */
3
+ export interface WorkerContext {
4
+ ticket: Ticket;
5
+ assignment: Assignment;
6
+ /** 预分配目录;为空表示由运行时决定。 */
7
+ workdir: string;
8
+ /** 运行时中立的工单契约;Router 正常都会提供,缺省时 adapter 可自行渲染。 */
9
+ brief?: WorkerBrief;
10
+ /** 报告文件路径;缺省时由 adapter 按 workersDir 推导。 */
11
+ report?: ReportPaths;
12
+ /** 工具策略;缺省时使用内置默认值。 */
13
+ tools?: ToolPolicy;
14
+ }
15
+ /** 运行时中立的任务契约:只讲“做什么/怎么上报”,不讲某个 CLI 的参数。 */
16
+ export interface WorkerBrief {
17
+ ticketId: string;
18
+ title: string;
19
+ scope: string;
20
+ workBranch: string;
21
+ /** 已渲染的正文(工单、授权范围、交付规则、上报命令)。 */
22
+ contract: string;
23
+ }
24
+ export interface ReportPaths {
25
+ statePath: string;
26
+ eventsPath: string;
27
+ }
28
+ /** 中立工具策略;adapter 负责映射到各 CLI 的开关。 */
29
+ export interface ToolPolicy {
30
+ fileAccess: 'read-only' | 'read-write';
31
+ /** deny=不给 shell;allowlist=只放行 shellAllow 中的命令前缀;allow=任意 shell。 */
32
+ shell: 'deny' | 'allowlist' | 'allow';
33
+ /** shell=allowlist 时生效,按命令前缀匹配,例如 ['ra report','ra doc','git','gh']。 */
34
+ shellAllow?: string[];
35
+ allowNetwork: boolean;
36
+ }
37
+ export interface InboundMessage {
38
+ /** 输入 id(in_xxx);投递时原样展示给 worker,用于写进 acked_inputs。 */
39
+ id: string;
40
+ kind: InputKind;
41
+ text: string;
42
+ }
43
+ export type ContextItem = {
44
+ kind: 'system-prompt';
45
+ text: string;
46
+ } | {
47
+ kind: 'file';
48
+ path: string;
49
+ content: string;
50
+ } | {
51
+ kind: 'env';
52
+ key: string;
53
+ value: string;
54
+ } | {
55
+ kind: 'dir';
56
+ path: string;
57
+ };
58
+ /** Router 传给运行时的引用:handle 不透明,其余字段让运行时能定位自己的 meta/会话。 */
59
+ export interface WorkspaceRequest {
60
+ ticketId: string;
61
+ repo: string;
62
+ baseBranch: string;
63
+ workBranch: string;
64
+ name: string;
65
+ workdir?: string;
66
+ }
67
+ export interface Workspace {
68
+ workspaceRef: string;
69
+ workdir: string;
70
+ branch: string;
71
+ meta?: Record<string, unknown>;
72
+ }
73
+ /** 内部构件:工作区生命周期。Orca 等运行时可以不严格实现。 */
74
+ export interface WorkspaceProvider {
75
+ readonly id: string;
76
+ create(req: WorkspaceRequest): Promise<Workspace>;
77
+ inspect(ref: string): Promise<WorkspaceInfo | null>;
78
+ /**
79
+ * 回收检出。`repo` 是源仓库绝对路径:git worktree remove 必须在 git 上下文里跑,
80
+ * 否则会报 `fatal: not a git repository`。
81
+ */
82
+ remove(ref: string, opts?: {
83
+ force?: boolean;
84
+ repo?: string;
85
+ }): Promise<void>;
86
+ listRepos?(): Promise<RepoDescriptor[]>;
87
+ }
88
+ export interface WorkerRef {
89
+ handle: string;
90
+ ticketId: string;
91
+ workdir?: string;
92
+ /** 运行时自己的会话 ID(Claude/Codex 用;Orca 可空)。 */
93
+ sessionId?: string;
94
+ }
95
+ /** 工作区引用:回收/查询时使用,不依赖 provider 私有选择器语法。 */
96
+ export interface WorkspaceRef {
97
+ ticketId: string;
98
+ workdir: string;
99
+ /** provider 自己的稳定标识;为空时由 workdir 推导。 */
100
+ workspaceRef?: string;
101
+ /** 源仓库绝对路径;回收检出时用它当 git 上下文。 */
102
+ repo?: string;
103
+ }
104
+ export interface StartResult {
105
+ handle: string;
106
+ workdir: string;
107
+ /** 实际工作分支(可能被 provider 加后缀);供 PR 兜底查询。 */
108
+ branch?: string;
109
+ /** 会话 ID;写入 runtime 的 meta.json,供 resume/活动定位。 */
110
+ sessionId?: string;
111
+ workspaceRef?: string;
112
+ }
113
+ export interface ActivityQuery {
114
+ ref: WorkerRef;
115
+ opts?: {
116
+ maxBytes?: number;
117
+ maxEvents?: number;
118
+ };
119
+ }
120
+ /** 投递回执:Router 据此决定是否重投;accepted 不等于 ack。 */
121
+ export type DeliveryReceipt = {
122
+ status: 'accepted';
123
+ inputIds: string[];
124
+ /**
125
+ * 运行时在投递过程中切换了会话(例如 Claude 的 resume 产生副本)。
126
+ * Router 必须把 Assignment 的 handle 换成新值,后续 status/stop 才能命中同一会话。
127
+ */
128
+ handle?: string;
129
+ sessionId?: string;
130
+ } | {
131
+ status: 'queued';
132
+ inputIds: string[];
133
+ reason?: string;
134
+ } | {
135
+ status: 'rejected';
136
+ inputIds: string[];
137
+ reason: string;
138
+ retryable?: boolean;
139
+ retryAfterMs?: number;
140
+ };
141
+ export interface DeliverOptions {
142
+ /** 第几次投递(从 1 开始);同一 attempt 的并发调用必须幂等。 */
143
+ attempt?: number;
144
+ /** Router 显式重投:adapter 必须允许同一 input.id 再次进入。 */
145
+ redeliver?: boolean;
146
+ }
147
+ export type AgentPhase = 'starting' | 'running' | 'blocked' | 'exited' | 'lost' | 'unknown';
148
+ export interface AgentStatus {
149
+ alive: boolean;
150
+ phase: AgentPhase;
151
+ acceptingInput: boolean;
152
+ /** 最后一次可观测活动时间(ISO);用于 idle / zombie 判定。 */
153
+ lastActivityAt?: string;
154
+ exitCode?: number;
155
+ exitSignal?: string;
156
+ /** provider 细节;只进日志,不进判断。 */
157
+ detail?: Record<string, unknown>;
158
+ }
159
+ export interface AgentOutput {
160
+ status: 'running' | 'exited' | 'unknown';
161
+ lines: string[];
162
+ source?: string;
163
+ }
164
+ /**
165
+ * 被中断的一轮执行。
166
+ *
167
+ * 运行时重启后用来回答「上一轮做到哪、是不是被中途打断的」。
168
+ * 只有进程会随 Router 一起死的运行时(capabilities.agent.processExit=true)
169
+ * 才有这个概念;常驻 worker 不会因为 Router 重启而中断,不需要实现。
170
+ */
171
+ export interface InterruptedTurn {
172
+ /** 运行时自己的轮次 id;用于去重,保证同一轮只提醒一次。 */
173
+ turnId: string;
174
+ /** 已执行到哪一步的简要描述;用来生成有意义的恢复提示。 */
175
+ summary?: string;
176
+ /** 中断发生时间(ISO),尽力而为。 */
177
+ at?: string;
178
+ }
179
+ /** 兼容旧命名。 */
180
+ export type TerminalOutput = AgentOutput;
181
+ /** Agent 会话记录里的一条活动(assistant 文本或工具调用)。 */
182
+ export interface SessionEvent {
183
+ at: string;
184
+ kind: 'text' | 'tool';
185
+ text: string;
186
+ tool?: {
187
+ name: string;
188
+ target?: string;
189
+ };
190
+ }
191
+ /** 从 Agent 自己的会话记录里读出的最近活动。 */
192
+ export interface SessionSnapshot {
193
+ at: string;
194
+ events: SessionEvent[];
195
+ sessionId?: string;
196
+ filePath?: string;
197
+ }
198
+ /** 人工接管会话时可直接粘贴到终端的恢复提示。 */
199
+ export interface ResumeHint {
200
+ /** 完整 shell 命令,已包含 cd 到工作目录。 */
201
+ command: string;
202
+ /** 运行时自己的会话 ID;用于展示与排障。 */
203
+ sessionId?: string;
204
+ /** 不阻断复制,但需要提示用户的注意事项。 */
205
+ note?: string;
206
+ }
207
+ export interface RuntimeCapabilities {
208
+ agent: {
209
+ liveStatus: boolean;
210
+ processExit: boolean;
211
+ output: boolean;
212
+ activity: boolean;
213
+ structuredInput: boolean;
214
+ nudge: boolean;
215
+ };
216
+ workspace: {
217
+ cleanup: boolean;
218
+ prLink: boolean;
219
+ discovery: boolean;
220
+ };
221
+ }
222
+ export interface RepoDescriptor {
223
+ name: string;
224
+ path: string;
225
+ kind?: string;
226
+ }
227
+ export interface WorkspaceInfo {
228
+ workdir: string;
229
+ branch: string;
230
+ dirty?: boolean;
231
+ linkedPr?: {
232
+ number: number;
233
+ url: string;
234
+ state?: 'open' | 'merged' | 'closed';
235
+ };
236
+ }
237
+ export interface DiagnosticCheck {
238
+ name: string;
239
+ status: 'ok' | 'warn' | 'fail';
240
+ detail: string;
241
+ hint?: string;
242
+ }
243
+ /** 运行时错误码;所有 adapter 必须抛 WorkerRuntimeError。 */
244
+ export type WorkerErrorCode = 'workspace:create-failed' | 'workspace:missing-repo' | 'workspace:missing-branch' | 'workspace:remove-failed' | 'agent:launch-failed' | 'agent:not-accepting-input' | 'agent:gone' | 'agent:timeout' | 'runtime:unavailable' | 'runtime:unknown';
245
+ export declare class WorkerRuntimeError extends Error {
246
+ readonly code: WorkerErrorCode;
247
+ readonly retryable: boolean;
248
+ readonly reason: string;
249
+ readonly cause?: string;
250
+ readonly detail?: Record<string, unknown>;
251
+ constructor(code: WorkerErrorCode, reason: string, opts?: {
252
+ retryable?: boolean;
253
+ cause?: string;
254
+ detail?: Record<string, unknown>;
255
+ });
256
+ }
257
+ /** Worker 运行时端口:换运行时只加一个 adapter,内核与 Router 不改。 */
258
+ export interface WorkerRuntime {
259
+ readonly id: string;
260
+ readonly capabilities: RuntimeCapabilities;
261
+ start(ctx: WorkerContext): Promise<StartResult>;
262
+ deliver(ref: WorkerRef, inputs: InboundMessage[], opts?: DeliverOptions): Promise<DeliveryReceipt>;
263
+ stop(ref: WorkerRef, reason: string): Promise<void>;
264
+ /** 可选:显式唤醒/探活;只有 capabilities.agent.nudge=true 时才实现。 */
265
+ nudge?(ref: WorkerRef): Promise<void>;
266
+ /** 可选:进程重启后把仍可恢复的会话接回来;接不回返回 false,不算丢失。 */
267
+ reattach?(ref: WorkerRef): Promise<boolean>;
268
+ /**
269
+ * 可选:查询上一轮是否被中途打断。
270
+ *
271
+ * 只有 worker 进程会随 Router 一起死的运行时(capabilities.agent.processExit=true)
272
+ * 才需要实现:这类运行时重启后「上一轮」确实可能停在半路。
273
+ * 返回 null 表示「没有被打断的轮次」或「判断不了」,不触发任何恢复动作。
274
+ */
275
+ interruptedTurn?(ref: WorkerRef): Promise<InterruptedTurn | null>;
276
+ /** 可选:结构化活性;返回 null 表示「无法判断」,不是「已丢失」。 */
277
+ status?(ref: WorkerRef): Promise<AgentStatus | null>;
278
+ /** 可选:输出尾部;没有则巡检跳过这一路。 */
279
+ output?(ref: WorkerRef, opts?: {
280
+ limit?: number;
281
+ }): Promise<AgentOutput | null>;
282
+ /** 可选:结构化活动;优先于 output。 */
283
+ activity?(query: ActivityQuery): Promise<SessionSnapshot | null>;
284
+ /** 可选:工作区查询/回收;不再使用运行时私有选择器。 */
285
+ inspectWorkspace?(ref: WorkspaceRef): Promise<WorkspaceInfo | null>;
286
+ removeWorkspace?(ref: WorkspaceRef): Promise<void>;
287
+ /** 可选:仓库发现(doctor / init)。 */
288
+ listRepos?(): Promise<RepoDescriptor[]>;
289
+ /** 可选:把本地仓库路径解析成 GitHub owner/repo,供 PR 跟踪。 */
290
+ repoSlug?(ref: WorkerRef): Promise<string | null>;
291
+ /** 可选:启动前自检。 */
292
+ doctor?(): Promise<DiagnosticCheck[]>;
293
+ /** 兼容保留:当前 Router 未调用。 */
294
+ registerContext?(ref: WorkerRef, items: ContextItem[]): Promise<void>;
295
+ }
package/dist/port.js ADDED
@@ -0,0 +1,17 @@
1
+ export class WorkerRuntimeError extends Error {
2
+ code;
3
+ retryable;
4
+ reason;
5
+ cause;
6
+ detail;
7
+ constructor(code, reason, opts = {}) {
8
+ super(reason);
9
+ this.name = 'WorkerRuntimeError';
10
+ this.code = code;
11
+ this.reason = reason;
12
+ this.retryable = opts.retryable ?? false;
13
+ this.cause = opts.cause;
14
+ this.detail = opts.detail;
15
+ }
16
+ }
17
+ //# sourceMappingURL=port.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"port.js","sourceRoot":"","sources":["../../../../packages/runtime/src/port.ts"],"names":[],"mappings":"AA6PA,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAClC,IAAI,CAAiB;IACrB,SAAS,CAAS;IAClB,MAAM,CAAQ;IACL,KAAK,CAAS;IACvB,MAAM,CAA0B;IAEzC,YACE,IAAqB,EACrB,MAAc,EACd,OAAkF,EAAE;QAEpF,KAAK,CAAC,MAAM,CAAC,CAAA;QACb,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAA;QAChC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;QACpB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,KAAK,CAAA;QACxC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAA;QACvB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAA;IAC3B,CAAC;CACF"}
@@ -0,0 +1,13 @@
1
+ import { type WorkerRuntime } from './port.js';
2
+ /** 按 id 持有运行时;内核只通过它取运行时,不直接 new OrcaRuntime。 */
3
+ export declare class RuntimeRegistry {
4
+ private readonly runtimes;
5
+ private readonly defaultId;
6
+ constructor(runtimes: Map<string, WorkerRuntime>, defaultId: string);
7
+ get(id: string): WorkerRuntime;
8
+ has(id: string): boolean;
9
+ ids(): string[];
10
+ default(): WorkerRuntime;
11
+ }
12
+ /** 用插件创建好的 adapter 组装注册表;插件发现与加载由 plugins/loader 负责。 */
13
+ export declare function createRuntimes(runtimes: Iterable<WorkerRuntime>, defaultId: string): RuntimeRegistry;
@@ -0,0 +1,35 @@
1
+ import { WorkerRuntimeError } from './port.js';
2
+ import { normalizeRuntimeId } from './runtimes/catalog.js';
3
+ /** 按 id 持有运行时;内核只通过它取运行时,不直接 new OrcaRuntime。 */
4
+ export class RuntimeRegistry {
5
+ runtimes;
6
+ defaultId;
7
+ constructor(runtimes, defaultId) {
8
+ this.runtimes = runtimes;
9
+ // 默认值可能来自旧配置(claude-cli),先归一再校验。
10
+ this.defaultId = normalizeRuntimeId(defaultId);
11
+ if (!runtimes.has(this.defaultId)) {
12
+ throw new WorkerRuntimeError('runtime:unknown', `默认 runtime 未注册: ${this.defaultId}`);
13
+ }
14
+ }
15
+ get(id) {
16
+ const runtime = this.runtimes.get(normalizeRuntimeId(id));
17
+ if (!runtime)
18
+ throw new WorkerRuntimeError('runtime:unknown', `未知 runtime: ${id}`);
19
+ return runtime;
20
+ }
21
+ has(id) {
22
+ return this.runtimes.has(normalizeRuntimeId(id));
23
+ }
24
+ ids() {
25
+ return [...this.runtimes.keys()];
26
+ }
27
+ default() {
28
+ return this.get(this.defaultId);
29
+ }
30
+ }
31
+ /** 用插件创建好的 adapter 组装注册表;插件发现与加载由 plugins/loader 负责。 */
32
+ export function createRuntimes(runtimes, defaultId) {
33
+ return new RuntimeRegistry(new Map([...runtimes].map(runtime => [runtime.id, runtime])), defaultId);
34
+ }
35
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../../packages/runtime/src/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAsB,MAAM,WAAW,CAAA;AAClE,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAC1D,iDAAiD;AACjD,MAAM,OAAO,eAAe;IAIP;IAHF,SAAS,CAAQ;IAElC,YACmB,QAAoC,EACrD,SAAiB;QADA,aAAQ,GAAR,QAAQ,CAA4B;QAGrD,iCAAiC;QACjC,IAAI,CAAC,SAAS,GAAG,kBAAkB,CAAC,SAAS,CAAC,CAAA;QAC9C,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;YAClC,MAAM,IAAI,kBAAkB,CAAC,iBAAiB,EAAE,mBAAmB,IAAI,CAAC,SAAS,EAAE,CAAC,CAAA;QACtF,CAAC;IACH,CAAC;IAED,GAAG,CAAC,EAAU;QACZ,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC,CAAA;QACzD,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,kBAAkB,CAAC,iBAAiB,EAAE,eAAe,EAAE,EAAE,CAAC,CAAA;QAClF,OAAO,OAAO,CAAA;IAChB,CAAC;IAED,GAAG,CAAC,EAAU;QACZ,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC,CAAA;IAClD,CAAC;IAED,GAAG;QACD,OAAO,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;IAClC,CAAC;IAED,OAAO;QACL,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;IACjC,CAAC;CACF;AAED,wDAAwD;AACxD,MAAM,UAAU,cAAc,CAAC,QAAiC,EAAE,SAAiB;IACjF,OAAO,IAAI,eAAe,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,CAAA;AACrG,CAAC"}
@@ -0,0 +1,58 @@
1
+ import type { ReportState } from '@router-agent/core/model.js';
2
+ export interface WorkerStateFile {
3
+ ticketId: string;
4
+ assignmentId: string;
5
+ turn: number;
6
+ state: ReportState;
7
+ summary: string;
8
+ humanAction?: string;
9
+ prNumber: number;
10
+ prUrl: string;
11
+ /** Worker 显式声明是否改了 UI;缺省时由 Router 按改动文件推断。 */
12
+ uiChange?: boolean;
13
+ reply?: string;
14
+ ackedInputs: string[];
15
+ updatedAt: string;
16
+ }
17
+ export interface WorkerMeta {
18
+ ticketId: string;
19
+ assignmentId: string;
20
+ handle: string;
21
+ workdir: string;
22
+ /** 运行时 id;ACP / Claude Code 会写入。 */
23
+ runtime?: string;
24
+ /** 底层 Agent 的真实会话 id;用于人工恢复。 */
25
+ sessionId?: string;
26
+ repo?: string;
27
+ [key: string]: unknown;
28
+ }
29
+ export interface PolledState {
30
+ state: WorkerStateFile;
31
+ meta: WorkerMeta | null;
32
+ mtimeMs: number;
33
+ }
34
+ export interface ReportPollerOptions {
35
+ workersDir: string;
36
+ onState: (state: WorkerStateFile, meta: WorkerMeta | null, path: string) => void;
37
+ onError?: (ticketId: string, error: Error) => void;
38
+ }
39
+ /** 轮询 ~/.router-agent/workers/<ticketId>/state.json,按文件内容增量上报。 */
40
+ export declare class ReportPoller {
41
+ private workersDir;
42
+ private onState;
43
+ private onError?;
44
+ private seen;
45
+ constructor(opts: ReportPollerOptions);
46
+ /** 扫描一轮,返回新上报数量。 */
47
+ scan(): number;
48
+ /** 清空基线,让下一轮重新上报(Router 重启对账时用)。 */
49
+ reset(): void;
50
+ }
51
+ export declare function parseStateFile(content: string, expectedTicketId?: string): {
52
+ ticketId: string;
53
+ state: WorkerStateFile;
54
+ };
55
+ /** 读取 worker 的 meta.json;供报告轮询与恢复命令共用。 */
56
+ export declare function readWorkerMeta(workersDir: string, ticketId: string): WorkerMeta | null;
57
+ /** 追加一条审计事件到 events.log。 */
58
+ export declare function appendEvent(path: string, event: Record<string, unknown>): void;
@@ -0,0 +1,130 @@
1
+ import { appendFileSync, existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { z } from 'zod';
4
+ /** 旧版 state.json 的交付物字段,仅用于向后兼容,不再参与新协议。 */
5
+ const LegacyDeliverableSchema = z.object({
6
+ kind: z.string().optional(),
7
+ content: z.string().default(''),
8
+ title: z.string().optional(),
9
+ url: z.string().default(''),
10
+ }).nullable().optional();
11
+ const StateSchema = z.object({
12
+ ticket_id: z.string().min(1),
13
+ assignment_id: z.string().default(''),
14
+ turn: z.coerce.number().int().min(0).default(0),
15
+ state: z.enum(['progress', 'ready', 'blocked', 'failed', 'dropped', 'waiting']),
16
+ summary: z.string().min(1),
17
+ human_action: z.string().nullable().optional(),
18
+ pr_number: z.coerce.number().int().min(0).default(0),
19
+ pr_url: z.string().default(''),
20
+ /** Worker 显式声明是否改了 UI;缺省时由 Router 按改动文件推断。 */
21
+ ui_change: z.boolean().optional(),
22
+ /** Worker 要发给发起人的完整回复(Markdown)。 */
23
+ reply: z.string().optional().default(''),
24
+ /** 旧版交付物字段,读取时拼进 reply。 */
25
+ deliverable: LegacyDeliverableSchema,
26
+ acked_inputs: z.array(z.string()).default([]),
27
+ updated_at: z.string().default(() => new Date().toISOString()),
28
+ });
29
+ /** 轮询 ~/.router-agent/workers/<ticketId>/state.json,按文件内容增量上报。 */
30
+ export class ReportPoller {
31
+ workersDir;
32
+ onState;
33
+ onError;
34
+ seen = new Map();
35
+ constructor(opts) {
36
+ this.workersDir = opts.workersDir;
37
+ this.onState = opts.onState;
38
+ this.onError = opts.onError;
39
+ }
40
+ /** 扫描一轮,返回新上报数量。 */
41
+ scan() {
42
+ if (!existsSync(this.workersDir))
43
+ return 0;
44
+ let count = 0;
45
+ const entries = readdirSync(this.workersDir, { withFileTypes: true });
46
+ for (const entry of entries) {
47
+ if (!entry.isDirectory())
48
+ continue;
49
+ const ticketId = entry.name;
50
+ const statePath = join(this.workersDir, ticketId, 'state.json');
51
+ if (!existsSync(statePath))
52
+ continue;
53
+ try {
54
+ const content = readFileSync(statePath, 'utf8');
55
+ const fingerprint = `${statSync(statePath).mtimeMs}:${content}`;
56
+ if (this.seen.get(ticketId) === fingerprint)
57
+ continue;
58
+ const { ticketId: parsedId, state } = parseStateFile(content, ticketId);
59
+ this.seen.set(ticketId, fingerprint);
60
+ const meta = readWorkerMeta(this.workersDir, ticketId);
61
+ this.onState({ ...state, ticketId: parsedId }, meta, statePath);
62
+ count += 1;
63
+ }
64
+ catch (error) {
65
+ this.onError?.(ticketId, error instanceof Error ? error : new Error(String(error)));
66
+ }
67
+ }
68
+ return count;
69
+ }
70
+ /** 清空基线,让下一轮重新上报(Router 重启对账时用)。 */
71
+ reset() {
72
+ this.seen.clear();
73
+ }
74
+ }
75
+ export function parseStateFile(content, expectedTicketId) {
76
+ let json;
77
+ try {
78
+ json = JSON.parse(content);
79
+ }
80
+ catch {
81
+ throw new Error('state:invalid-json');
82
+ }
83
+ const parsed = StateSchema.safeParse(json);
84
+ if (!parsed.success)
85
+ throw new Error(`state:invalid: ${parsed.error.issues.map(i => i.path.join('.')).join(',')}`);
86
+ if (expectedTicketId && parsed.data.ticket_id !== expectedTicketId) {
87
+ throw new Error(`state:ticket-mismatch: 目录 ${expectedTicketId} 收到 ${parsed.data.ticket_id}`);
88
+ }
89
+ const data = parsed.data;
90
+ const legacy = data.deliverable;
91
+ // 旧版 deliverable 升级成纯回复:正文 + 链接,不再保留 kind。
92
+ const reply = data.reply.trim() || [legacy?.content?.trim(), legacy?.url?.trim()].filter(Boolean).join('\n\n');
93
+ return {
94
+ ticketId: data.ticket_id,
95
+ state: {
96
+ ticketId: data.ticket_id,
97
+ assignmentId: data.assignment_id,
98
+ turn: data.turn,
99
+ state: data.state,
100
+ summary: data.summary,
101
+ ...(data.human_action ? { humanAction: data.human_action } : {}),
102
+ prNumber: data.pr_number,
103
+ prUrl: data.pr_url,
104
+ ...(data.ui_change !== undefined ? { uiChange: data.ui_change } : {}),
105
+ ...(reply ? { reply } : {}),
106
+ ackedInputs: data.acked_inputs,
107
+ updatedAt: data.updated_at,
108
+ },
109
+ };
110
+ }
111
+ /** 读取 worker 的 meta.json;供报告轮询与恢复命令共用。 */
112
+ export function readWorkerMeta(workersDir, ticketId) {
113
+ const path = join(workersDir, ticketId, 'meta.json');
114
+ if (!existsSync(path))
115
+ return null;
116
+ try {
117
+ return JSON.parse(readFileSync(path, 'utf8'));
118
+ }
119
+ catch {
120
+ return null;
121
+ }
122
+ }
123
+ /** 追加一条审计事件到 events.log。 */
124
+ export function appendEvent(path, event) {
125
+ mkdirSync(join(path, '..'), { recursive: true });
126
+ if (!existsSync(path))
127
+ writeFileSync(path, '', 'utf8');
128
+ appendFileSync(path, `${JSON.stringify(event)}\n`, 'utf8');
129
+ }
130
+ //# sourceMappingURL=report-poller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report-poller.js","sourceRoot":"","sources":["../../../../packages/runtime/src/report-poller.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * 人工恢复命令的拼装与运行时映射。
3
+ *
4
+ * 恢复命令只依赖三件事:工作目录、底层 Agent 的真实 session id、该 Agent 的 CLI
5
+ * 语法。这里用一张静态表把这些知识集中起来,不要求每个运行时实现额外方法。
6
+ * 只生成 POSIX shell(sh/bash/zsh)可执行的一行命令;动态值全部单引号转义。
7
+ */
8
+ import type { ResumeHint } from './port.js';
9
+ /** 单个运行时的 CLI 恢复模板。 */
10
+ export interface ResumeSpec {
11
+ /** 有真实 sessionId 时执行的命令。 */
12
+ command?: string;
13
+ /** 有真实 sessionId 时的参数模板,支持 {sessionId}。 */
14
+ args?: readonly string[];
15
+ /** 没有 sessionId、但有运行时 handle 时的备用命令;缺省复用 command。 */
16
+ handleCommand?: string;
17
+ /** 没有 sessionId、但有运行时 handle 时的备用模板,支持 {handle}。 */
18
+ handleArgs?: readonly string[];
19
+ /** handle 兜底命令是否需要在 workdir 里执行;默认 true。Orca 的终端切换与目录无关。 */
20
+ handleRequiresWorkdir?: boolean;
21
+ /** 有 sessionId 时附加的提示。 */
22
+ note?: string;
23
+ /** 走 handle 备用模板时附加的提示。 */
24
+ handleNote?: string;
25
+ }
26
+ /** 按运行时 id 取恢复模板;未知/未核实返回 null。 */
27
+ export declare function resumeSpecOf(runtimeId: string, agentId?: string): ResumeSpec | null;
28
+ export interface ResumeSource {
29
+ workdir?: string;
30
+ /** 底层 Agent 的真实会话 id;优先级最高。 */
31
+ sessionId?: string;
32
+ /** 运行时自己的短句柄;没有 sessionId 时用于 attach 类命令。 */
33
+ handle?: string;
34
+ /** 由外部决定用哪个 Agent 的运行时(如 Orca)需要它来选恢复命令。 */
35
+ agentId?: string;
36
+ }
37
+ /**
38
+ * 根据运行时与会话信息生成恢复命令。
39
+ *
40
+ * @param workdirExists 由调用方传入,保持本模块为纯函数;false 时追加工作区提示。
41
+ */
42
+ export declare function buildResumeHint(runtimeId: string, source: ResumeSource, opts?: {
43
+ workdirExists?: boolean;
44
+ }): ResumeHint | null;
45
+ /** 单引号转义;内部单引号写成 '\''。 */
46
+ export declare function shellQuote(value: string): string;
47
+ /**
48
+ * 生成 `cd <workdir> && <command> <args...>`。
49
+ *
50
+ * `command` 只应来自上面的可信常量,不作为用户输入参与转义;workdir 与参数一律转义。
51
+ */
52
+ export declare function resumeCommand(workdir: string, command: string, args?: readonly string[]): string;