agent-cli-runtime 0.1.0-alpha.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 (151) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/CONTRIBUTING.md +60 -0
  3. package/LICENSE +202 -0
  4. package/README.md +573 -0
  5. package/README.zh-CN.md +571 -0
  6. package/SECURITY.md +35 -0
  7. package/dist/adapters/adapter-types.d.ts +138 -0
  8. package/dist/adapters/adapter-types.js +2 -0
  9. package/dist/adapters/adapter-types.js.map +1 -0
  10. package/dist/adapters/claude.d.ts +2 -0
  11. package/dist/adapters/claude.js +97 -0
  12. package/dist/adapters/claude.js.map +1 -0
  13. package/dist/adapters/codex.d.ts +3 -0
  14. package/dist/adapters/codex.js +120 -0
  15. package/dist/adapters/codex.js.map +1 -0
  16. package/dist/adapters/opencode.d.ts +4 -0
  17. package/dist/adapters/opencode.js +111 -0
  18. package/dist/adapters/opencode.js.map +1 -0
  19. package/dist/adapters/registry.d.ts +9 -0
  20. package/dist/adapters/registry.js +23 -0
  21. package/dist/adapters/registry.js.map +1 -0
  22. package/dist/cli/main.d.ts +2 -0
  23. package/dist/cli/main.js +978 -0
  24. package/dist/cli/main.js.map +1 -0
  25. package/dist/core/async-queue.d.ts +10 -0
  26. package/dist/core/async-queue.js +49 -0
  27. package/dist/core/async-queue.js.map +1 -0
  28. package/dist/core/diagnostics.d.ts +20 -0
  29. package/dist/core/diagnostics.js +4 -0
  30. package/dist/core/diagnostics.js.map +1 -0
  31. package/dist/core/event-contract.d.ts +32 -0
  32. package/dist/core/event-contract.js +128 -0
  33. package/dist/core/event-contract.js.map +1 -0
  34. package/dist/core/events.d.ts +147 -0
  35. package/dist/core/events.js +4 -0
  36. package/dist/core/events.js.map +1 -0
  37. package/dist/core/ids.d.ts +1 -0
  38. package/dist/core/ids.js +5 -0
  39. package/dist/core/ids.js.map +1 -0
  40. package/dist/core/redaction.d.ts +4 -0
  41. package/dist/core/redaction.js +51 -0
  42. package/dist/core/redaction.js.map +1 -0
  43. package/dist/core/runtime.d.ts +41 -0
  44. package/dist/core/runtime.js +83 -0
  45. package/dist/core/runtime.js.map +1 -0
  46. package/dist/core/schema-contract.d.ts +55 -0
  47. package/dist/core/schema-contract.js +143 -0
  48. package/dist/core/schema-contract.js.map +1 -0
  49. package/dist/detection/detect.d.ts +14 -0
  50. package/dist/detection/detect.js +293 -0
  51. package/dist/detection/detect.js.map +1 -0
  52. package/dist/detection/env.d.ts +2 -0
  53. package/dist/detection/env.js +15 -0
  54. package/dist/detection/env.js.map +1 -0
  55. package/dist/detection/executable-resolution.d.ts +12 -0
  56. package/dist/detection/executable-resolution.js +50 -0
  57. package/dist/detection/executable-resolution.js.map +1 -0
  58. package/dist/detection/invocation.d.ts +9 -0
  59. package/dist/detection/invocation.js +22 -0
  60. package/dist/detection/invocation.js.map +1 -0
  61. package/dist/goals/goal-scheduler.d.ts +31 -0
  62. package/dist/goals/goal-scheduler.js +518 -0
  63. package/dist/goals/goal-scheduler.js.map +1 -0
  64. package/dist/goals/goal-store.d.ts +37 -0
  65. package/dist/goals/goal-store.js +300 -0
  66. package/dist/goals/goal-store.js.map +1 -0
  67. package/dist/goals/goal-types.d.ts +103 -0
  68. package/dist/goals/goal-types.js +2 -0
  69. package/dist/goals/goal-types.js.map +1 -0
  70. package/dist/goals/planner-prompts.d.ts +3 -0
  71. package/dist/goals/planner-prompts.js +26 -0
  72. package/dist/goals/planner-prompts.js.map +1 -0
  73. package/dist/goals/task-graph.d.ts +9 -0
  74. package/dist/goals/task-graph.js +229 -0
  75. package/dist/goals/task-graph.js.map +1 -0
  76. package/dist/goals/validation-runner.d.ts +7 -0
  77. package/dist/goals/validation-runner.js +63 -0
  78. package/dist/goals/validation-runner.js.map +1 -0
  79. package/dist/index.d.ts +11 -0
  80. package/dist/index.js +2 -0
  81. package/dist/index.js.map +1 -0
  82. package/dist/parsers/claude-stream-json.d.ts +11 -0
  83. package/dist/parsers/claude-stream-json.js +102 -0
  84. package/dist/parsers/claude-stream-json.js.map +1 -0
  85. package/dist/parsers/codex-json.d.ts +8 -0
  86. package/dist/parsers/codex-json.js +107 -0
  87. package/dist/parsers/codex-json.js.map +1 -0
  88. package/dist/parsers/line-buffer.d.ts +7 -0
  89. package/dist/parsers/line-buffer.js +28 -0
  90. package/dist/parsers/line-buffer.js.map +1 -0
  91. package/dist/parsers/opencode-json.d.ts +8 -0
  92. package/dist/parsers/opencode-json.js +72 -0
  93. package/dist/parsers/opencode-json.js.map +1 -0
  94. package/dist/parsers/plain-lines.d.ts +6 -0
  95. package/dist/parsers/plain-lines.js +9 -0
  96. package/dist/parsers/plain-lines.js.map +1 -0
  97. package/dist/public-types.d.ts +143 -0
  98. package/dist/public-types.js +2 -0
  99. package/dist/public-types.js.map +1 -0
  100. package/dist/runs/process-runner.d.ts +35 -0
  101. package/dist/runs/process-runner.js +97 -0
  102. package/dist/runs/process-runner.js.map +1 -0
  103. package/dist/runs/prompt-transport.d.ts +10 -0
  104. package/dist/runs/prompt-transport.js +43 -0
  105. package/dist/runs/prompt-transport.js.map +1 -0
  106. package/dist/runs/run-result.d.ts +9 -0
  107. package/dist/runs/run-result.js +22 -0
  108. package/dist/runs/run-result.js.map +1 -0
  109. package/dist/runs/run-scheduler.d.ts +25 -0
  110. package/dist/runs/run-scheduler.js +552 -0
  111. package/dist/runs/run-scheduler.js.map +1 -0
  112. package/dist/runs/run-store.d.ts +42 -0
  113. package/dist/runs/run-store.js +297 -0
  114. package/dist/runs/run-store.js.map +1 -0
  115. package/dist/runs/run-types.d.ts +59 -0
  116. package/dist/runs/run-types.js +2 -0
  117. package/dist/runs/run-types.js.map +1 -0
  118. package/dist/smoke/parser-samples.d.ts +17 -0
  119. package/dist/smoke/parser-samples.js +186 -0
  120. package/dist/smoke/parser-samples.js.map +1 -0
  121. package/dist/storage/file-storage.d.ts +35 -0
  122. package/dist/storage/file-storage.js +271 -0
  123. package/dist/storage/file-storage.js.map +1 -0
  124. package/dist/storage/jsonl-store.d.ts +9 -0
  125. package/dist/storage/jsonl-store.js +138 -0
  126. package/dist/storage/jsonl-store.js.map +1 -0
  127. package/dist/storage/manifest-validation.d.ts +11 -0
  128. package/dist/storage/manifest-validation.js +102 -0
  129. package/dist/storage/manifest-validation.js.map +1 -0
  130. package/dist/storage/storage-lease.d.ts +40 -0
  131. package/dist/storage/storage-lease.js +223 -0
  132. package/dist/storage/storage-lease.js.map +1 -0
  133. package/dist/storage/storage-types.d.ts +55 -0
  134. package/dist/storage/storage-types.js +2 -0
  135. package/dist/storage/storage-types.js.map +1 -0
  136. package/dist/storage/store-inspection.d.ts +28 -0
  137. package/dist/storage/store-inspection.js +941 -0
  138. package/dist/storage/store-inspection.js.map +1 -0
  139. package/docs/api-schema-contract.md +92 -0
  140. package/docs/compatibility.md +832 -0
  141. package/docs/daemon-ready-contract.md +283 -0
  142. package/docs/production-readiness.md +281 -0
  143. package/docs/release-checklist.md +257 -0
  144. package/docs/release-publish-runbook.md +201 -0
  145. package/docs/release-report.md +517 -0
  146. package/docs/ssot.md +1257 -0
  147. package/examples/cli-dogfood.md +113 -0
  148. package/examples/library-goal.js +94 -0
  149. package/examples/library-run.js +84 -0
  150. package/package.json +79 -0
  151. package/scripts/dogfood.mjs +243 -0
@@ -0,0 +1,571 @@
1
+ # Agent CLI Runtime
2
+
3
+ > 一个轻量、本地优先的 runtime,用同一套 typed API 驱动 Codex CLI、Claude Code、OpenCode 以及其他 coding-agent CLI。
4
+
5
+ [![License: Apache-2.0](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](./LICENSE)
6
+ [![Status: pre-alpha](https://img.shields.io/badge/status-pre--alpha-orange.svg)](#项目状态)
7
+
8
+ [English](./README.md) | [简体中文](./README.zh-CN.md)
9
+
10
+ Agent CLI Runtime 是一个 adapter layer。它适合你在不想重新造一个 coding agent 的时候,把多个本地 agent CLI 接到自己的产品、脚本或桌面应用里。
11
+
12
+ 现代本地 coding agent 已经知道如何规划、编辑文件、运行工具、请求权限、管理 session、调用模型。这个项目把这些 agent loop 留在用户已安装的 CLI 内部,只在外面提供一层小而可靠的 runtime:
13
+
14
+ - 检测本机已安装的 coding agents;
15
+ - 在指定 `cwd` 启动 agent;
16
+ - 通过 stdin 等安全 transport 传递 prompt;
17
+ - 把不同 CLI 的 streaming output 归一成同一种 event protocol;
18
+ - 支持 cancel、timeout、diagnose 和 run result classification;
19
+ - 让 permissions 和 extra readable directories 保持显式。
20
+
21
+ ## 项目状态
22
+
23
+ 本仓库目前处于 **pre-alpha / developer preview**。
24
+
25
+ 发布边界说明:
26
+ - 这是 P3-7 API / CLI schema freeze 阶段,不承诺稳定 API,也不是 npm 发布记录。
27
+ - P3-11 将 current-head release-candidate 证据保存在 npm 包外的 `.release-evidence/`;包内文档只描述稳定流程和人工门禁 alpha publish 边界。
28
+ - `createAgentRuntime` 是当前公开的主要 value 入口,其他 adapter/parser/store 内部实现不对外承诺。
29
+ - 这版不包含后台 daemon、API server、WAL、database 或 remote runtime 模式承诺。
30
+ - 运行时定位是可嵌入 daemon/product shell 的 local-first execution kernel,不替代托管平台服务。
31
+
32
+ API 与 CLI schema 契约在 [docs/api-schema-contract.md](./docs/api-schema-contract.md),daemon-ready 嵌入契约在 [docs/daemon-ready-contract.md](./docs/daemon-ready-contract.md),SSOT 在 [docs/ssot.md](./docs/ssot.md),release-candidate 证据入口在 [docs/release-report.md](./docs/release-report.md),未来 alpha 发布 runbook 在 [docs/release-publish-runbook.md](./docs/release-publish-runbook.md)。当前实现是 contract-hardening 的 library-first Node.js/TypeScript 版本,默认 memory-only run / goal 调度,可选 durable local replay storage 及 crash/recovery health reporting,并补充 fault-injected consistency coverage、package-root API contract tests、tarball TypeScript consumer smoke 和 installed-package daemon embedding verification;包含内置 CLI compatibility profiles、强化后的 planner/task-graph validation、版本化 event/diagnostics/conformance/real-smoke/store/release-artifact 契约、parser fixtures、本地/远端 release artifact verification、remote CI/artifact audit checks、alpha publish readiness docs,以及本地 smoke/query 薄 CLI。
33
+
34
+ ## 为什么需要它
35
+
36
+ 每个严肃的 coding-agent 产品,最后都会遇到同一组朴素但锋利的 runtime 问题:
37
+
38
+ | 问题 | Runtime 负责什么 |
39
+ | --- | --- |
40
+ | 用户安装的 CLI 各不相同 | 检测 Codex CLI、Claude Code、OpenCode 和未来 adapter |
41
+ | 每个 CLI 的 flags 不同 | 把 argv construction 收进 adapter definition |
42
+ | 长 prompt 会撞上 argv 长度限制 | 默认优先使用 stdin 或 prompt file |
43
+ | stream schema 各不相同 | 把各 agent output 解析成统一 `AgentEvent` stream |
44
+ | headless run 可能卡住 | 提供 cancellation、timeout、inactivity 和 exit classification |
45
+ | permission 很容易给过头 | 让 `cwd`、`extraAllowedDirs`、`permissionPolicy` 明确可见 |
46
+
47
+ 目标是把这一层做得足够可靠、足够无聊,让更优秀的工具可以放心构建在它上面。
48
+
49
+ ## 它不是什么
50
+
51
+ Agent CLI Runtime 不是:
52
+
53
+ - LLM provider router;
54
+ - hosted cloud agent;
55
+ - Codex CLI、Claude Code 或 OpenCode 的替代品;
56
+ - web UI;
57
+ - plugin marketplace;
58
+ - 自研 `Read` / `Write` / `Edit` tool loop;
59
+ - permission bypass wrapper。
60
+
61
+ Runtime delegate agent loop。它归一的是执行过程,不是智能本身。
62
+
63
+ ## API
64
+
65
+ ```ts
66
+ import { createAgentRuntime } from "agent-cli-runtime";
67
+
68
+ const runtime = createAgentRuntime();
69
+
70
+ const agents = await runtime.detect({
71
+ includeUnavailable: true,
72
+ });
73
+
74
+ const run = await runtime.run({
75
+ agentId: "codex",
76
+ cwd: "/path/to/project",
77
+ prompt: "Add a focused regression test for the failing parser case.",
78
+ permissionPolicy: "workspace-write",
79
+ });
80
+
81
+ for await (const event of run.events) {
82
+ if (event.type === "text_delta") process.stdout.write(event.text);
83
+ if (event.type === "tool_call") console.log("tool", event.name);
84
+ if (event.type === "error") console.error(event.code, event.message);
85
+ }
86
+ ```
87
+
88
+ Goal 会先启动一次 planner run,再用 dependency-aware ready queue 执行 task graph:
89
+
90
+ ```ts
91
+ const goal = await runtime.createGoal({
92
+ cwd: "/path/to/project",
93
+ objective: "实现一个聚焦的 parser regression fix。",
94
+ defaultAgentId: "codex",
95
+ permissionPolicy: "workspace-write",
96
+ maxConcurrentTasks: 2,
97
+ retryPolicy: {
98
+ maxAttempts: 2,
99
+ retryableErrorCodes: ["AGENT_TIMEOUT", "AGENT_EXECUTION_FAILED"],
100
+ backoffMs: 500,
101
+ },
102
+ });
103
+
104
+ for await (const event of goal.events) {
105
+ if (event.type === "task_attempt_started") console.log(event.taskId, event.attemptId, event.runId);
106
+ if (event.type === "goal_finished") console.log(event.result);
107
+ }
108
+ ```
109
+
110
+ task 只有在所有 dependencies 都 `succeeded` 后才会进入 ready。默认 `maxConcurrentTasks: 1`,保持保守串行语义;在 `createGoal()` 或 `createAgentRuntime()` 上配置后,互不冲突的 ready tasks 才会并发执行。`retryPolicy` 默认 `{ maxAttempts: 1 }`;只有 terminal error code 命中 `retryableErrorCodes` 的失败才会重试。cancel 和 validation failure 默认不重试,除非 caller 显式把对应 error code 加进 retry policy。
111
+
112
+ Planner output 会在任何 task 启动前先被校验。主路径仍是 strict JSON,但 runtime 可以从 Markdown fenced code 或短的 surrounding prose 中提取唯一一个 JSON object。多个 JSON objects、malformed JSON、缺少 `tasks` 或字段类型非法时,planning 会以 `AGENT_TASK_GRAPH_INVALID` 写入 `scheduler_error`,goal 最终为 `failed`;这些错误不会被误报成 task failure 或 adapter unavailable。Diagnostics 保持简短,不会把超长 planner 原文完整写入输出。
113
+
114
+ Task graph schema:
115
+
116
+ ```json
117
+ {
118
+ "tasks": [
119
+ {
120
+ "id": "T001",
121
+ "title": "短标题",
122
+ "objective": "自包含任务目标",
123
+ "dependencies": [],
124
+ "allowedFiles": ["src/example.ts"],
125
+ "validationCommands": ["npm test"],
126
+ "agentId": "codex",
127
+ "retryPolicy": {
128
+ "maxAttempts": 2,
129
+ "retryableErrorCodes": ["AGENT_TIMEOUT"],
130
+ "backoffMs": 250
131
+ }
132
+ }
133
+ ]
134
+ }
135
+ ```
136
+
137
+ `id`、`title`、`objective` 和每个 `dependencies` item 都必须是 string。`dependencies`、`allowedFiles`、`validationCommands` 和 `retryPolicy.retryableErrorCodes` 必须是 string array。`agentId` 如存在必须是 string。task-level `retryPolicy` 如存在,必须包含正整数 `maxAttempts`、string array `retryableErrorCodes` 和非负 number `backoffMs`。
138
+
139
+ 每个 task evidence 会记录 attempts:
140
+
141
+ ```json
142
+ {
143
+ "runId": "run_latest",
144
+ "result": "success",
145
+ "attempts": [
146
+ {
147
+ "attemptId": "T001:attempt:1",
148
+ "runId": "run_1",
149
+ "startedAt": 1760000000000,
150
+ "finishedAt": 1760000001200,
151
+ "result": "failed",
152
+ "diagnostics": [{ "code": "AGENT_EXECUTION_FAILED", "message": "..." }]
153
+ },
154
+ {
155
+ "attemptId": "T001:attempt:2",
156
+ "runId": "run_2",
157
+ "startedAt": 1760000001800,
158
+ "finishedAt": 1760000002600,
159
+ "result": "success",
160
+ "diagnostics": []
161
+ }
162
+ ],
163
+ "validationCommands": [],
164
+ "summary": "Task T001 finished with success after 2 attempts."
165
+ }
166
+ ```
167
+
168
+ 持久化是显式开启的:不传 `storageDir` 时,run 和 goal 仍然只保存在内存里;传入 `storageDir` 后,runtime 会写入可审计的 JSON manifest 和 JSONL replay events:
169
+
170
+ ```ts
171
+ const runtime = createAgentRuntime({
172
+ storageDir: ".agent-runtime",
173
+ storage: { durability: "fsync" }, // 可选;默认是 "relaxed"
174
+ });
175
+
176
+ const runs = await runtime.listRuns({ status: "active" });
177
+ const runEvents = await runtime.replayRunEvents("run_123", { afterEventId: 10 });
178
+ const goals = await runtime.listGoals();
179
+ const goalEvents = await runtime.replayGoalEvents("goal_123");
180
+ ```
181
+
182
+ Public facade 暴露:
183
+
184
+ - `createAgentRuntime(options?)`
185
+ - `runtime.detect(options?)`
186
+ - `runtime.detectStream(options?)`
187
+ - `runtime.run(request)`
188
+ - `runtime.createGoal(request)`
189
+ - `runtime.cancelRun(runId)`
190
+ - `runtime.cancelGoal(goalId)`
191
+ - `runtime.shutdown(reason?)`
192
+ - `runtime.getRun(runId)`
193
+ - `runtime.replayRunEvents(runId, { afterEventId? })`
194
+ - `runtime.listRuns({ status? })`
195
+ - `runtime.getGoal(goalId)`
196
+ - `runtime.replayGoalEvents(goalId, { afterEventId? })`
197
+ - `runtime.listGoals({ status? })`
198
+ - `runtime.inspectStore({ storageDir? })`
199
+ - `runtime.exportDiagnostics({ kind: "run", runId, storageDir? })`
200
+ - `runtime.exportDiagnostics({ kind: "goal", goalId, storageDir? })`
201
+ - `runtime.getAdapter(id)`
202
+
203
+ ### API 契约边界
204
+
205
+ Pre-alpha release 的 package root 会刻意保持小。它只导出 `createAgentRuntime()` 这个运行时 value,以及调用 runtime、消费 records 所需的 public TypeScript types:
206
+
207
+ - stable MVP surface:`AgentRuntime`、`RuntimeOptions`、`DetectOptions`、`DetectedAgent`、`RunRequest`、`RunHandle`、`RunRecord`、`RunStatus`、`CreateGoalRequest`、`GoalHandle`、`GoalRecord`、`GoalStatus`、`AgentEvent`、`SchedulerEvent`、`ReplayEvent`、`VersionedEventEnvelope`、`EventScope`、`EventTerminalContract`、`EventTerminalReason`、`RuntimeDiagnostic` 和 `RuntimeErrorCode`;
208
+ - experimental extension surface:adapter authoring 相关类型,例如 `AgentAdapterDef`、`BuildArgsInput`、`PromptTransport`、`StreamParser` 和 `AdapterCompatibilityProfile`;
209
+ - 不从 package root 导出:内置 adapter values、parser helpers、executable-resolution helpers、stores、schedulers 和 task-graph helpers。
210
+
211
+ 发布 tarball 里可能包含内部 `dist/` 文件,因为 TypeScript declarations 和 CLI 需要它们;但文档承诺的 API 边界只有 package root import:`import { createAgentRuntime } from "agent-cli-runtime"`。
212
+
213
+ `getAdapter(id)` 和 `RuntimeOptions.adapters` 是 pre-alpha 阶段为 adapter 实验保留的 extension points;在 stable release 之前,它们的形状仍可能调整。
214
+
215
+ ## Pre-alpha API 发布边界
216
+
217
+ - 本阶段不承诺稳定 API 契约。
218
+ - 包根仅承诺运行时 facade 的稳定入口,内部 adapter / parser / store 实现不对外承诺。
219
+ - 本阶段不提供 daemon、WAL、remote runtime 等稳定化能力。
220
+ - CLI JSON schemas 与 failure taxonomy 遵循 [docs/api-schema-contract.md](./docs/api-schema-contract.md) 中的 pre-alpha versioning policy。
221
+
222
+ ## 安装
223
+
224
+ 从 npm 安装:
225
+
226
+ ```bash
227
+ npm install agent-cli-runtime
228
+ ```
229
+
230
+ 不安装到项目、直接用 `npx` 调 CLI:
231
+
232
+ ```bash
233
+ npx --package agent-cli-runtime agent-runtime agents --json
234
+ npx --package agent-cli-runtime agent-runtime conformance --mode fixtures --json
235
+ ```
236
+
237
+ 从本仓库本地 checkout 使用:
238
+
239
+ ```bash
240
+ npm ci
241
+ npm run build
242
+ node ./dist/cli/main.js --help
243
+ npm run daemon:verify
244
+ npm run dogfood
245
+ ```
246
+
247
+ 安装后的最小 library smoke:
248
+
249
+ ```bash
250
+ node -e "import('agent-cli-runtime').then((m) => console.log(typeof m.createAgentRuntime))"
251
+ ```
252
+
253
+ 最小 TypeScript consumer:
254
+
255
+ ```ts
256
+ import {
257
+ createAgentRuntime,
258
+ type CreateGoalRequest,
259
+ type RunRequest,
260
+ } from "agent-cli-runtime";
261
+
262
+ const runtime = createAgentRuntime({ storageDir: "./.agent-runtime" });
263
+
264
+ const runRequest: RunRequest = {
265
+ agentId: "codex",
266
+ cwd: process.cwd(),
267
+ prompt: "Reply with a one-line status.",
268
+ };
269
+
270
+ const goalRequest: CreateGoalRequest = {
271
+ defaultAgentId: "codex",
272
+ cwd: process.cwd(),
273
+ objective: "Summarize this repository.",
274
+ };
275
+
276
+ void runRequest;
277
+ void goalRequest;
278
+ void runtime.shutdown();
279
+ ```
280
+
281
+ Daemon embedding gate 会把 packed tarball 安装到临时 consumer,再用 fake CLI 跑 detect/conformance、run、goal、replay、diagnostics、store inspection、shutdown 和 reopen。Runtime safety gate 使用同样的 installed-package 边界,覆盖 repeated run/goal、慢 event consumer、cancel/timeout churn、repeated shutdown、lease close 和 reopen:
282
+
283
+ ```bash
284
+ npm run daemon:verify
285
+ npm run runtime:safety
286
+ ```
287
+
288
+ 更完整的 release gate 会把 packed tarball 安装到临时 TypeScript 项目,执行 `tsc --noEmit`,再用 fake CLI 跑 library run / goal / replay / diagnostics smoke。见 `npm run daemon:verify`、`npm run runtime:safety`、`npm run dogfood` 和 [docs/release-checklist.md](./docs/release-checklist.md)。
289
+
290
+ 本机 agent CLI 按场景安装即可:
291
+
292
+ - `codex`(Codex CLI)
293
+ - `claude`(Claude Code)
294
+ - `opencode` / `opencode-cli`(OpenCode)
295
+
296
+ Executable override:
297
+
298
+ ```bash
299
+ export CODEX_BIN=/absolute/path/to/codex
300
+ export CLAUDE_BIN=/absolute/path/to/claude
301
+ export OPENCODE_BIN=/absolute/path/to/opencode
302
+ ```
303
+
304
+ Codex 配置继承已安装 Codex CLI 和当前进程环境。runtime 不替用户登录、不编辑 Codex config,也不会偷偷提升权限。
305
+
306
+ Claude Code 可以使用它的默认 first-party 配置,也可以接 Anthropic-compatible provider。provider 配置只通过环境变量名说明,不在文档、示例、fixture、manifest 中写真实 token:
307
+
308
+ ```bash
309
+ export ANTHROPIC_BASE_URL=<anthropic-compatible-base-url>
310
+ export ANTHROPIC_MODEL=<model-name>
311
+ export ANTHROPIC_DEFAULT_OPUS_MODEL=<model-name>
312
+ export ANTHROPIC_DEFAULT_SONNET_MODEL=<model-name>
313
+ export ANTHROPIC_DEFAULT_HAIKU_MODEL=<model-name>
314
+ export CLAUDE_CODE_SUBAGENT_MODEL=<model-name>
315
+ export CLAUDE_CODE_EFFORT_LEVEL=<effort>
316
+ # 按 provider 或 Claude Code 配置要求设置 token 变量,
317
+ # 常见名称包括 ANTHROPIC_AUTH_TOKEN 或 ANTHROPIC_API_KEY;不要提交变量值。
318
+ ```
319
+
320
+ OpenCode 配置继承已安装 OpenCode CLI。当前 runtime 使用 `opencode run --format json --dir <cwd>`;显式 read-only/workspace-write flag、extra dirs 和 session 仍留在 `needsVerification`,直到有真实 CLI 证据。
321
+
322
+ 代理和网络相关环境变量按需设置:
323
+
324
+ ```bash
325
+ export HTTPS_PROXY=http://127.0.0.1:7897
326
+ export HTTP_PROXY=http://127.0.0.1:7897
327
+ ```
328
+
329
+ 发布前本地验证命令:
330
+
331
+ ```bash
332
+ npm run ci
333
+ npm run daemon:verify
334
+ npm run runtime:safety
335
+ npm run dogfood
336
+ npm run prepublish:check
337
+ node ./dist/cli/main.js conformance --mode fixtures --json
338
+ node ./dist/cli/main.js conformance --mode fake --json
339
+ node ./dist/cli/main.js conformance --mode real --agent all --json
340
+ node ./dist/cli/main.js smoke --mode real --agent codex --json
341
+ ```
342
+
343
+ `conformance --mode real` 和 `smoke --mode real` 不带 `--allow-real-run` 时只做真实本地 detection/profile certification,不启动 authenticated real agent run。只有显式传入 `--allow-real-run` 才会执行真实 run;未传 `--cwd` 时 runtime 使用隔离临时目录,并请求 read-only 行为。请把 `--allow-real-run` 当成本机账号/网络 run 的明确安全边界。
344
+
345
+ CI 使用 Node.js 20/22/24 matrix 跑 typecheck、lint、tests、build、production dependency audit、package boundary check 和 `npm pack --dry-run`。`npm run daemon:verify`、`npm run runtime:safety` 和 `npm run dogfood` 放在单 Node 版本 release-gates job 中执行,避免 matrix 重复跑 installed-package gates。dogfood、CI 和 prepublish 的默认边界一致:允许 fixtures、fake CLIs、真实本地 detection/profile certification;不带 `--allow-real-run` 时不启动 authenticated real agent run。
346
+
347
+ 本地 release-candidate 置信门禁使用 `npm run prepublish:check`。它会组合 typecheck、lint、tests、build、daemon embedding verification、runtime safety verification、dogfood、production audit、package boundary check 和 pack dry-run。GitHub Actions 的 `Release Candidate` workflow 通过 `workflow_dispatch` 手动触发,执行 `npm ci`、`npm run ci`、`npm run dogfood` 和 `npm run release:candidate -- --out-dir release-candidate`;生成并上传 `agent-cli-runtime-tarball`、`agent-cli-runtime-pack-metadata`、`agent-cli-runtime-package-files`、`agent-cli-runtime-gate-evidence` 和 `agent-cli-runtime-release-verification`。P3-10 提交证据文档前的 release-candidate 证据是 SHA `fdba3ebccb2e57a0ad295101028a2a3937a92204` 的 run `27945938663`,五个下载 artifacts 已通过 `npm run release:verify -- --dir /tmp/agent-runtime-p3-10-current-head-remote-66VIhN/normalized`,schema 为 `agent-cli-runtime.releaseVerification.v1`。由于 release docs 会进入 npm package,提交本证据 packet 会改变 package shasum;run `27945938663` 不能作为提交这些文档后的最终发布证据。人工发布 packet 的 stop point 是 `npm publish --dry-run --ignore-scripts --tag alpha`;npm publish 尚未发生,真实发布前必须在提交本 packet 后重新触发 fresh release-candidate run。历史 P3-9 run `27943672095` 只证明目标 SHA `65fac505ca3eb830a06d8656068cf4ed5f6dd46a`;历史 P3-9 interim run `27942743285` 只证明 strict `fixtures?` package-boundary lock 之前的目标 SHA `a0299a7d81bb614661922bebc8c75496cf0a3d11`;历史 P3-8 run `27940814340` 只证明目标 SHA `eb8de0f9b1edfa3f94c35a50b31005c5d3c105d4`;历史 P3-5 run `27932628093` 只证明 workflow head SHA `8d7bc2a19c626caa1ad5223acbcd35df34aff18e`。它不执行 publish,也不需要 npm token。
348
+
349
+ 如需在本地生成可审查的 release-candidate artifact set:
350
+
351
+ ```bash
352
+ npm run release:candidate -- --out-dir release-candidate
353
+ npm run release:verify -- --dir release-candidate
354
+ ```
355
+
356
+ `release:candidate` 会在输出目录写入 `npm-pack.json`、`package-files.txt`、`gate-evidence.json`、tarball 和 `release-verification.json`。`release:verify` 也可用于下载 GitHub Actions artifacts 后复核同一组文件,并确认候选包记录了 `daemon:verify` 和 `runtime:safety` 证据。
357
+
358
+ Release evidence summary 见 [docs/release-report.md](./docs/release-report.md),alpha publish decision runbook 见 [docs/release-publish-runbook.md](./docs/release-publish-runbook.md)。`npm publish --dry-run --ignore-scripts --tag alpha` 只作为本地手动 dry-run check 记录在这些文档中;它不得真的 publish,也不作为远端 CI 必选 gate。
359
+
360
+ 可运行示例见 [examples/library-run.js](./examples/library-run.js)、[examples/library-goal.js](./examples/library-goal.js) 和 [examples/cli-dogfood.md](./examples/cli-dogfood.md)。两个 JavaScript 示例会创建本地 fake CLI,不需要真实 provider secret。
361
+
362
+ ## CLI
363
+
364
+ ```bash
365
+ agent-runtime agents
366
+ agent-runtime conformance --mode fixtures --json
367
+ agent-runtime conformance --mode fake --json
368
+ agent-runtime conformance --mode real --agent all --json
369
+ agent-runtime smoke --mode real --agent codex --allow-real-run --expect-text <safe_text> --json
370
+ agent-runtime smoke --mode real --agent claude --allow-real-run --expect-text <safe_text> --json
371
+ agent-runtime smoke --mode real --agent opencode --allow-real-run --expect-text <safe_text> --json
372
+ agent-runtime smoke --mode detection --json
373
+ agent-runtime smoke --mode fixtures --json
374
+ agent-runtime run --agent codex --cwd . --prompt "fix the failing test"
375
+ agent-runtime goal --agent codex --cwd . --prompt "split this objective into tasks and execute them"
376
+ agent-runtime goal --agent codex --cwd . --prompt "run independent fixes" --max-concurrent-tasks 2 --max-attempts 2 --retryable-error-codes AGENT_TIMEOUT,AGENT_EXECUTION_FAILED
377
+ agent-runtime run --agent claude --cwd . --permission workspace-write --prompt-file task.md
378
+ agent-runtime run --agent codex --cwd . --prompt "fix the failing test" --json
379
+ agent-runtime run --agent codex --cwd . --prompt "fix the failing test" --stream jsonl --diagnostics
380
+ agent-runtime doctor
381
+ agent-runtime runs --storage-dir .agent-runtime --json
382
+ agent-runtime run-status run_123 --storage-dir .agent-runtime --json
383
+ agent-runtime replay-run run_123 --storage-dir .agent-runtime --after 10 --jsonl
384
+ agent-runtime goals --storage-dir .agent-runtime --json
385
+ agent-runtime goal-status goal_123 --storage-dir .agent-runtime --json
386
+ agent-runtime replay-goal goal_123 --storage-dir .agent-runtime --after 10 --jsonl
387
+ agent-runtime store-health --storage-dir .agent-runtime --json
388
+ agent-runtime store-lock --storage-dir .agent-runtime --json
389
+ agent-runtime store-repair --storage-dir .agent-runtime --dry-run --json
390
+ agent-runtime store-repair --storage-dir .agent-runtime --apply --json
391
+ agent-runtime diagnostics run run_123 --storage-dir .agent-runtime --json
392
+ agent-runtime diagnostics goal goal_123 --storage-dir .agent-runtime --json --out diagnostics-goal_123.json
393
+ agent-runtime smoke --mode real --agent codex --allow-real-run --prompt-file task.md --expect-text "expected reply" --timeout-ms 30000 --json --diagnostics
394
+ ```
395
+
396
+ Library API 是主入口。CLI 是同一套 runtime 之上的薄包装,并支持 `--json` 以及 run/goal 的 `--stream jsonl` event stream。对 run/goal 命令,`--json` 输出最终 run 或 goal record;`--stream jsonl --diagnostics` 保留事件流,并在 terminal event 后追加一行 redacted `run_summary` 或 `goal_summary`。
397
+
398
+ `agent-runtime conformance` 是正式 production gate 包装。它的 JSON 输出带 `schemaVersion: "agent-runtime.conformance.v1"`,并输出稳定的 per-adapter summary,字段包括 `adapter`、`version`、`resolvedExecutable`、`auth`、`modelsSource`、`capabilities`、`argvProfile`、`promptTransport`、`parserMode`、`runClassification`、`expectedTextMatched`、`observedTextTail`、`cwdMutationChecked`、`cwdMutated`、`diagnosticsCount`、`diagnostics`、`skippedReason` 和 `failureReason`。
399
+
400
+ - `--mode fixtures` 离线检查 parser contract。
401
+ - `--mode fake` 临时创建 fake CLIs,并通过真实 adapter argv/stdin/parser 路径离线执行。
402
+ - `--mode real` 默认只执行真实本地 detection/profile certification,不启动 agent run。只有显式传入 `--allow-real-run` 时才启动真实运行;否则可运行 adapter 会返回 `runClassification: "real_run_skipped"` 和 `skippedReason: "real_run_not_allowed"`。`--agent all` 会把单个 adapter 的 fail/skip 隔离在 summary 中,不吞掉其他 adapter 结果。
403
+
404
+ Real conformance 也负责 drift detection:tracked flag 不再出现在 help 中、version/help 输出形状异常、parser/stream 失败、未验证能力都会变成 actionable diagnostics,而不是猜一个新 flag 塞进 argv。未知能力保留在 `argvProfile.needsVerification`。输出会对 token、Bearer、auth env assignment、prompt、observed text tail 和真实私有绝对路径做脱敏。
405
+
406
+ `agent-runtime smoke` 有三个模式:
407
+
408
+ - `--mode detection` 只执行本地 executable/model/auth detection。
409
+ - `--mode fixtures` 离线 dry-run Codex、Claude、OpenCode 的内置 parser conformance fixtures,不启动真实 CLI。
410
+ - `--mode real` 默认只做 detection/profile certification,并返回 `runClassification: "real_run_skipped"`;只有显式传入 `--allow-real-run` 才会启动真实 run。带 `--allow-real-run` 时,它会为 `--agent <id>` 执行一次真实非写入 run,并由 runtime 请求 read-only 行为。未传 `--cwd` 时使用隔离临时目录。默认 prompt 要求 agent 精确回复 `agent-runtime <agent> smoke ok` 且不编辑文件;`--expect-text <text>` 可指定另一段安全验收文本。expected text 是成功的必要条件:如果传入 `--prompt` 或 `--prompt-file` 但未传 `--expect-text`,即使 exit `0` 且有 text 输出,也会分类为 `unexpected_output`。
411
+
412
+ 推荐的 opt-in smoke evidence 命令:
413
+
414
+ ```bash
415
+ node ./dist/cli/main.js smoke --mode real --agent codex --allow-real-run --expect-text <safe_text> --json
416
+ node ./dist/cli/main.js smoke --mode real --agent claude --allow-real-run --expect-text <safe_text> --json
417
+ node ./dist/cli/main.js smoke --mode real --agent opencode --allow-real-run --expect-text <safe_text> --json
418
+ ```
419
+
420
+ Real smoke JSON 使用 `schemaVersion: "agent-runtime.realSmoke.v1"`,输出 redacted `real_smoke_summary`,字段包括 `adapter`、`version`、`auth`、`modelsSource`、`runClassification`、`expectedTextMatched`、截断脱敏的 `observedTextTail`、`cwdMutationChecked`、`cwdMutated`、`diagnosticsCount`、`skippedReason` 和 `failureReason`。它不包含 prompt text、token value、私有 cwd、raw stdout/stderr 或最终 run record。失败和跳过分类包括 `auth_missing`、`unavailable_executable`、`unsupported_flag`、`unexpected_output`、`cwd_mutated`、`needs_verification` 和 `real_run_skipped`。
421
+
422
+ 完整 schema inventory 和 version bump policy,包括 event envelopes、diagnostics、conformance、real smoke、store health/repair、CLI errors、release verification 与 release gate evidence,统一维护在 [docs/api-schema-contract.md](./docs/api-schema-contract.md)。
423
+
424
+ 磁盘布局保持简单、方便人工检查和 `tail`:
425
+
426
+ ```text
427
+ .agent-runtime/
428
+ runtime.lock.json
429
+ runs/<runId>/manifest.json
430
+ runs/<runId>/events.jsonl
431
+ goals/<goalId>/manifest.json
432
+ goals/<goalId>/events.jsonl
433
+ ```
434
+
435
+ Public replay API 保持 source-compatible,仍返回 `ReplayEvent<T>`:`{ "id": 1, "sequence": 1, "runId": "run_123", "timestamp": 123, "event": {...} }`,goal event 使用同样形状但带 `goalId`。CLI JSONL 输出,包括 `run --stream jsonl`、`goal --stream jsonl`、`replay-run --jsonl` 和 `replay-goal --jsonl`,统一使用稳定 envelope `schemaVersion: "agent-runtime.event.v1"`:
436
+
437
+ ```json
438
+ {
439
+ "schemaVersion": "agent-runtime.event.v1",
440
+ "id": 1,
441
+ "sequence": 1,
442
+ "timestamp": 1760000000000,
443
+ "scope": { "kind": "run", "id": "run_123" },
444
+ "event": { "type": "run_finished", "result": "success", "timestamp": 1760000000000 },
445
+ "terminal": { "result": "success", "reason": "success" }
446
+ }
447
+ ```
448
+
449
+ `id` 和 `sequence` 在单个 run 或 goal 内单调递增。Terminal reason 使用同一组词:`success`、`failed`、`timeout`、`canceled`、`interrupted`、`validation_failed`、`execution_failed`、`unavailable`、`auth_missing`、`task_graph_invalid`。`--stream jsonl --diagnostics` 可能在 event envelopes 后追加一行脱敏 summary。默认 durability 是 `relaxed`;`createAgentRuntime({ storageDir, storage: { durability: "fsync" } })` 会要求 store 对 manifest temp file 和 event append 尽量执行 `fdatasync` / `fsync`,并在平台不支持时 graceful fallback、记录 diagnostics。
450
+
451
+ 传入 `storageDir` 时,runtime 会以 writer mode 打开本地 single-writer lease,写在 `runtime.lock.json`。lock owner 包含生成的 `runtimeInstanceId`、`pid`、`startedAt` 和 `heartbeatAt`;active run/goal manifest 也会记录当前 owner。同一个 `storageDir` 若已有 live owner,第二个 writer runtime 会被拒绝。如果已有 owner stale 或 closed,新 runtime 可以接管,并记录脱敏 lease diagnostic。`runtime.shutdown(reason?)` 会取消 active runs/goals,短暂等待 terminal events,并把 lease 标记为 closed。这只是同一台机器上的 best-effort 嵌入式 runtime 防护;不是 daemon coordination、distributed lock、WAL、数据库事务层,也不是 live process resume。
452
+
453
+ 新的 writer runtime 指向同一个 `storageDir` 后可以直接读取 terminal run/goal。只有 owner missing、stale 或 closed 的 active record 会进入 interrupted recovery;这些 run/goal 会被标记为 failed,并写入 `AGENT_RUNTIME_INTERRUPTED` diagnostic/event,避免重启后假装仍在执行。属于另一个 live runtime owner 的 active record 不会被改写,只通过只读 inspection 暴露。损坏的 manifest 或 JSONL 行只影响对应 record,并通过 `AGENT_STORE_RECORD_CORRUPT` 或 `AGENT_EVENT_LOG_CORRUPT` diagnostic 暴露,不会拖垮 runtime 初始化。加载 corrupt manifest 时不会静默覆盖原始坏文件,因此后续 health scan 仍能看到损坏证据。
454
+
455
+ `runs`、`goals`、`run-status`、`goal-status`、`replay-run`、`replay-goal`、`store-health`、`store-lock` 和 `diagnostics` 都是针对指定 `storageDir` 的只读 inspection path;它们不会获取 writer lease,也不会中断 active work。`store-lock` 输出当前 lock owner/status。`store-health` 使用 `schemaVersion: "agent-runtime.storeHealth.v1"`,会扫描磁盘 store,不启动 agent。输出包含 lock status、带 owner live/stale/closed 状态的 active records、run/goal 总数、corrupt manifests、corrupt event logs、corrupt line count、partial JSONL tail detection、retained event count、last good event id/sequence、repair recommendation、历史 active/interrupted records、storage-level sync/lease diagnostics,以及一致性 warnings。中间坏 JSONL 行会被跳过,后续合法 records 仍可 replay;partial tail 会停在最后一个确认完整的 record boundary。terminal manifest 缺 terminal event、event log 有 terminal event 但 manifest 非 terminal,都会报告 warning;runtime 不会静默替用户改写。
456
+
457
+ `store-repair --json` 默认等同于非破坏性的 `--dry-run`,输出 `schemaVersion: "agent-runtime.storeRepair.v1"`。partial tail 报告为 `truncate_partial_tail`;中间坏行报告为 `isolate_corrupt_line`;terminal manifest/event mismatch 只进入 `manual_review`,不会自动修 manifest。`--apply` 必须显式传入且要求 `--storage-dir`,遇到 live writer owner 会拒绝执行;写入期间会持有本地 store lease,把原始 event log 备份到 `repair-backups/<timestamp>/...`,再用 temp file + rename 和 best-effort fsync 写回。如果 backup 创建失败,不会改写原 event log;如果 backup 已创建但 rewrite 失败,report 会保留 backup path,原 event log 仍保持可读,不会变成半截 rewrite。成功 apply 会把 `AGENT_STORE_REPAIR_APPLIED` 记录为 redacted storage diagnostic;失败 apply 会记录 `AGENT_STORE_REPAIR_FAILED`,方便后续 health 和 diagnostics bundle 展示修复证据。apply 保守且幂等;它不是 WAL、数据库事务层、daemon resume 或 compaction 服务。
458
+
459
+ Diagnostics bundle 是单个 run 或 goal 的 redacted JSON 证据包。bundle 使用 `schemaVersion: "agent-runtime.diagnostics.v1"`,包含脱敏 manifest、event summary(不是完整 event payload)、`RuntimeDiagnostic[]` items、storage-level diagnostics、goal task attempt evidence(如存在)、带 terminal reason 和 owner/lease 状态的 supervisor summary,以及 environment-safe adapter summary。带 `--json` 的 CLI usage failure 使用 `schemaVersion: "agent-runtime.cliError.v1"`。`--out <file>` 使用 temp file + rename 原子写入。bundle、health output 和 JSON error 不包含原始损坏 JSONL 行、token、Bearer value、auth-token 环境变量赋值、完整 env dump、prompt 或绝对私密路径。
460
+
461
+ Production readiness 范围见 [docs/production-readiness.md](./docs/production-readiness.md)。本项目的 local-first production 目标是单机、本地 CLI、显式 `storageDir`、local single-writer lease、可审计且脱敏的 diagnostics、无静默提权;daemon/API server、WAL、live resume/session attachment、distributed execution、UI/artifacts、telemetry 和 database 层仍不属于本包能力。
462
+
463
+ ## 配置
464
+
465
+ Pre-alpha 包优先使用环境变量配置。用 `CODEX_BIN`、`CLAUDE_BIN`、`OPENCODE_BIN` 指定 executable;proxy 和 provider 变量从父进程继承;token 不进入 prompt 和已提交文件。
466
+
467
+ 当前真实 CLI smoke matrix 见 [docs/compatibility.md](./docs/compatibility.md)。
468
+
469
+ ## Runtime Model
470
+
471
+ ```mermaid
472
+ flowchart LR
473
+ App["Your app or script"] --> Runtime["Agent CLI Runtime"]
474
+ Runtime --> Registry["Adapter registry"]
475
+ Registry --> Codex["Codex CLI"]
476
+ Registry --> Claude["Claude Code"]
477
+ Registry --> OpenCode["OpenCode"]
478
+ Codex --> Events["AgentEvent stream"]
479
+ Claude --> Events
480
+ OpenCode --> Events
481
+ Events --> App
482
+ ```
483
+
484
+ 每个 adapter 只负责真正因 CLI 而异的部分:
485
+
486
+ - binary names 和 env overrides;
487
+ - version、auth、capability、model probes;
488
+ - verified / unverified invocation flags 的 compatibility profile notes;
489
+ - argv construction;
490
+ - prompt transport;
491
+ - stream parser;
492
+ - permission-policy mapping。
493
+
494
+ Core runner 负责 process lifecycle、process-tree best-effort termination、diagnostics、cancellation、timeout、shutdown、redaction 和 event delivery。
495
+
496
+ ## MVP Adapters
497
+
498
+ | Adapter | Target binary | Prompt transport | Stream strategy | MVP status |
499
+ | --- | --- | --- | --- | --- |
500
+ | Codex CLI | `codex` | stdin | `codex exec --json` | P1-6 real smoke 要求 expected text 证据并检查 cwd mutation;timeout diagnostics 可分类本地网络/plugin startup 卡顿;transient reconnect events 会解析成 status |
501
+ | Claude Code | `claude` | stdin JSONL | `stream-json` | P0-4 已记录 detection baseline;本地 auth 仍 missing |
502
+ | OpenCode | `opencode-cli`, `opencode` | stdin | JSON stream | P1-6 非写入 isolated smoke 会检查 expected text 和 cwd mutation;本机 `opencode` 1.15.6 的 stdin prompt support 已验证,显式 read-only flags 仍未验证 |
503
+
504
+ 未来新增 adapter 应该不需要改 core runtime。
505
+
506
+ ## Event Protocol
507
+
508
+ Runtime 暴露一个小而 append-only 的 event stream:
509
+
510
+ ```ts
511
+ type AgentEvent =
512
+ | { type: "run_started"; runId: string; agentId: string; cwd: string; model?: string; timestamp: number }
513
+ | { type: "status"; label: string; detail?: string; timestamp: number }
514
+ | { type: "text_delta"; text: string; timestamp: number }
515
+ | { type: "thinking_delta"; text: string; timestamp: number }
516
+ | { type: "tool_call"; id: string; name: string; input?: unknown; timestamp: number }
517
+ | { type: "tool_result"; id: string; output?: unknown; isError?: boolean; timestamp: number }
518
+ | { type: "file_event"; path: string; action: "created" | "updated" | "deleted" | "unknown"; timestamp: number }
519
+ | { type: "usage"; usage: RuntimeUsage; costUsd?: number; timestamp: number }
520
+ | { type: "error"; code: RuntimeErrorCode; message: string; retryable?: boolean; detail?: unknown; timestamp: number }
521
+ | { type: "run_finished"; result: "success" | "failed" | "cancelled"; exitCode?: number | null; signal?: string | null; timestamp: number };
522
+ ```
523
+
524
+ Goal scheduling 会把 run events 包装成 `goal_started`、`task_created`、`task_started`、`task_attempt_started`、`run_event`、`task_attempt_finished`、`task_finished`、`goal_finished` 和 `scheduler_error`。
525
+
526
+ Adapter-specific raw events 可以进入 debug log,但 public API 应保持稳定、小而清晰。
527
+
528
+ ## Security Model
529
+
530
+ 这个项目会代表 caller 启动本地进程。这件事能力很强,所以默认边界必须明确。
531
+
532
+ - Runtime 不替用户登录 agent CLI。
533
+ - MVP 中 runtime 不编辑用户 CLI config files。
534
+ - Metadata probes 运行在 neutral temp directory,而不是用户项目目录。
535
+ - Prompt 应优先使用 stdin 或 prompt file,而不是 argv。
536
+ - `cwd` 必须显式指定。
537
+ - `extraAllowedDirs` 必须显式指定。
538
+ - Permission escalation 必须显式指定。
539
+ - Logs 和 diagnostics 必须 redact secret-looking env values 和 tokens。
540
+ - Disk backed storage 不写入 secret-bearing environment maps;diagnostics 以及 validation stdout/stderr 会先 redaction,再写入 manifest 或 events。
541
+ - 单个 adapter 失败不能导致其他 adapter detection 一起失败。
542
+ - Detection probe diagnostics 会分类为 `not_installed`、`not_executable`、`auth_missing`、`network_error`、`unsupported_flag` 或 `probe_failed`。
543
+ - JSON stream parser 会忽略空行、warning、log 和非 JSON 噪声行;用户可见正文只来自结构化 CLI text 字段。
544
+ - Timeout diagnostics 会记录 sanitized argv/profile labels、parsed event count、stdout/stderr tail 和 actionable hints;prompt 仍然不会进入 argv。
545
+ - Goal task 的 `validationCommands` 会在 agent run 成功后由 runtime 在 task `cwd` 执行;validation 失败会把 task 和 goal 标记为 failed。
546
+
547
+ Runtime 不应授予超过 caller 明确请求的权限。
548
+
549
+ ## 与其他项目的关系
550
+
551
+ Agent CLI Runtime 受到 [OpenDesign](https://github.com/nexu-io/open-design) 的 adapter/runtime boundary 启发,也参考了 [OpenCode](https://github.com/anomalyco/opencode) 在开源项目呈现上的清晰度。
552
+
553
+ 本项目不隶属于 OpenDesign、OpenCode、Anthropic、OpenAI 或任何被支持 CLI 的 vendor。
554
+
555
+ ## Roadmap
556
+
557
+ - M0:SSOT、README、license、project skeleton。已完成。
558
+ - M1:core process runner with fake CLI tests。已完成。
559
+ - M2:Codex adapter MVP。已完成。
560
+ - M3:Claude Code adapter MVP。已完成。
561
+ - M4:OpenCode adapter MVP。已完成。
562
+ - M5:CLI wrapper 和 `doctor` command。已完成。
563
+ - M6:public package boundary、compatibility matrix、API/CLI contract freeze、contribution guide、security policy。已完成(pre-alpha 发布候选硬化)。
564
+
565
+ ## Contributing
566
+
567
+ 请参见 [CONTRIBUTING.md](./CONTRIBUTING.md)。
568
+
569
+ ## License
570
+
571
+ Apache License 2.0。见 [LICENSE](./LICENSE)。
package/SECURITY.md ADDED
@@ -0,0 +1,35 @@
1
+ # Security Policy
2
+
3
+ Thank you for helping keep `agent-cli-runtime` safe.
4
+
5
+ ## Reporting a security issue
6
+
7
+ - Open an issue in this repository with a clear reproduction path and sample log snippets (redacted).
8
+ - If you believe the issue could cause immediate impact, report it as a private advisory through the repository's security/contact channel and include:
9
+ - impact scenario,
10
+ - affected version,
11
+ - proof steps,
12
+ - suggested timeline.
13
+ - Do not paste raw tokens, session identifiers, or absolute private paths in issue text.
14
+
15
+ ## Secrets and redaction policy
16
+
17
+ - This project redacts secret-looking values at diagnostic and event boundaries.
18
+ - `redactText` and `redactUnknown` are required for:
19
+ - tokens / Bearer-like values,
20
+ - auth-token assignments (for example `ANTHROPIC_AUTH_TOKEN`, `OPENAI_API_KEY`, etc.),
21
+ - private absolute paths and similar local environment evidence.
22
+ - Storage diagnostics and redacted exports must not include raw values from secrets or absolute private paths.
23
+
24
+ ## Repository content rules
25
+
26
+ - Do not commit real tokens, real CLI outputs, or raw private paths in docs, fixtures, or test artifacts.
27
+ - `docs/fixtures`, when present in future, must not include `sk-*`, `Bearer`, or real auth/session values.
28
+ - The `.reference/` tree is source-of-inspiration only and must not be published via package files.
29
+
30
+ ## Runtime boundaries
31
+
32
+ - The runtime must not bypass the user CLI permission model.
33
+ - `cwd`, `extraAllowedDirs`, and permission policy selection are explicit and visible in request inputs.
34
+ - If a runtime behavior request requires stronger privilege than currently expressed in `RunRequest`, the feature must be explicitly surfaced as a non-default request path before implementation.
35
+