@orion-agents/orion-code 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/README.md +73 -14
  3. package/README.zh-CN.md +63 -14
  4. package/bin/orion +15 -4
  5. package/dist/cli.js +51 -172
  6. package/dist/cli.js.map +1 -1
  7. package/dist/commands/model-command-handlers.d.ts +2 -2
  8. package/dist/commands/model-command-handlers.d.ts.map +1 -1
  9. package/dist/commands/model-command-handlers.js +113 -32
  10. package/dist/commands/model-command-handlers.js.map +1 -1
  11. package/dist/commands/session-command-handlers.d.ts.map +1 -1
  12. package/dist/commands/session-command-handlers.js +106 -15
  13. package/dist/commands/session-command-handlers.js.map +1 -1
  14. package/dist/commands/types.d.ts +13 -3
  15. package/dist/commands/types.d.ts.map +1 -1
  16. package/dist/commands/types.js +1 -1
  17. package/dist/commands/types.js.map +1 -1
  18. package/dist/index.d.ts +1 -1
  19. package/dist/index.js +1 -1
  20. package/dist/runtime/agent-loop.d.ts.map +1 -1
  21. package/dist/runtime/agent-loop.js +3 -3
  22. package/dist/runtime/agent-loop.js.map +1 -1
  23. package/dist/runtime/agent-runtime-controller.d.ts +32 -1
  24. package/dist/runtime/agent-runtime-controller.d.ts.map +1 -1
  25. package/dist/runtime/agent-runtime-controller.js +242 -27
  26. package/dist/runtime/agent-runtime-controller.js.map +1 -1
  27. package/dist/runtime/agent-runtime-runner.d.ts +2 -1
  28. package/dist/runtime/agent-runtime-runner.d.ts.map +1 -1
  29. package/dist/runtime/legacy-thread-materializer.d.ts +18 -0
  30. package/dist/runtime/legacy-thread-materializer.d.ts.map +1 -1
  31. package/dist/runtime/legacy-thread-materializer.js +27 -12
  32. package/dist/runtime/legacy-thread-materializer.js.map +1 -1
  33. package/dist/runtime/orion-runtime-v1.d.ts +2 -0
  34. package/dist/runtime/orion-runtime-v1.d.ts.map +1 -1
  35. package/dist/runtime/orion-runtime-v1.js +7 -1
  36. package/dist/runtime/orion-runtime-v1.js.map +1 -1
  37. package/dist/runtime/orion-session-runner.d.ts +7 -2
  38. package/dist/runtime/orion-session-runner.d.ts.map +1 -1
  39. package/dist/runtime/orion-session-runner.js +16 -6
  40. package/dist/runtime/orion-session-runner.js.map +1 -1
  41. package/dist/runtime/product-bootstrap.d.ts +22 -0
  42. package/dist/runtime/product-bootstrap.d.ts.map +1 -0
  43. package/dist/runtime/product-bootstrap.js +374 -0
  44. package/dist/runtime/product-bootstrap.js.map +1 -0
  45. package/dist/runtime/product-orion-runtime.d.ts +2 -1
  46. package/dist/runtime/product-orion-runtime.d.ts.map +1 -1
  47. package/dist/runtime/product-orion-runtime.js +83 -13
  48. package/dist/runtime/product-orion-runtime.js.map +1 -1
  49. package/dist/runtime/protocol/runtime-protocol-v1.d.ts +1 -1
  50. package/dist/runtime/protocol/runtime-protocol-v1.js +1 -1
  51. package/dist/runtime/protocol/runtime-protocol-v1.js.map +1 -1
  52. package/dist/runtime/release-receipts.d.ts +63 -3
  53. package/dist/runtime/release-receipts.d.ts.map +1 -1
  54. package/dist/runtime/release-receipts.js +297 -7
  55. package/dist/runtime/release-receipts.js.map +1 -1
  56. package/dist/runtime/step-snapshot.d.ts.map +1 -1
  57. package/dist/runtime/step-snapshot.js +22 -2
  58. package/dist/runtime/step-snapshot.js.map +1 -1
  59. package/dist/runtime/subagents/runtime-integration.d.ts +1 -1
  60. package/dist/runtime/subagents/runtime-integration.d.ts.map +1 -1
  61. package/dist/runtime/subagents/runtime-integration.js +5 -2
  62. package/dist/runtime/subagents/runtime-integration.js.map +1 -1
  63. package/dist/runtime/thread-event-store.d.ts +27 -0
  64. package/dist/runtime/thread-event-store.d.ts.map +1 -1
  65. package/dist/runtime/thread-event-store.js +119 -17
  66. package/dist/runtime/thread-event-store.js.map +1 -1
  67. package/dist/runtime/thread-projection.d.ts +10 -0
  68. package/dist/runtime/thread-projection.d.ts.map +1 -1
  69. package/dist/runtime/thread-projection.js +40 -0
  70. package/dist/runtime/thread-projection.js.map +1 -1
  71. package/dist/runtime/thread-runtime.d.ts +3 -1
  72. package/dist/runtime/thread-runtime.d.ts.map +1 -1
  73. package/dist/runtime/thread-runtime.js +6 -0
  74. package/dist/runtime/thread-runtime.js.map +1 -1
  75. package/dist/runtime/thread-session-view.d.ts +43 -0
  76. package/dist/runtime/thread-session-view.d.ts.map +1 -1
  77. package/dist/runtime/thread-session-view.js +85 -22
  78. package/dist/runtime/thread-session-view.js.map +1 -1
  79. package/dist/runtime/thread-ui-adapter.d.ts +2 -0
  80. package/dist/runtime/thread-ui-adapter.d.ts.map +1 -1
  81. package/dist/runtime/thread-ui-adapter.js +126 -4
  82. package/dist/runtime/thread-ui-adapter.js.map +1 -1
  83. package/dist/runtime/ui-events.d.ts +35 -0
  84. package/dist/runtime/ui-events.d.ts.map +1 -1
  85. package/dist/runtime/ui-events.js +1 -0
  86. package/dist/runtime/ui-events.js.map +1 -1
  87. package/dist/runtime/ui-view-model.d.ts +2 -0
  88. package/dist/runtime/ui-view-model.d.ts.map +1 -1
  89. package/dist/runtime/ui-view-model.js +7 -3
  90. package/dist/runtime/ui-view-model.js.map +1 -1
  91. package/dist/services/global-config.d.ts +25 -0
  92. package/dist/services/global-config.d.ts.map +1 -1
  93. package/dist/services/global-config.js +373 -5
  94. package/dist/services/global-config.js.map +1 -1
  95. package/dist/services/session-storage.d.ts +59 -0
  96. package/dist/services/session-storage.d.ts.map +1 -1
  97. package/dist/services/session-storage.js +303 -101
  98. package/dist/services/session-storage.js.map +1 -1
  99. package/dist/services/settings-coordinator.d.ts +174 -0
  100. package/dist/services/settings-coordinator.d.ts.map +1 -0
  101. package/dist/services/settings-coordinator.js +605 -0
  102. package/dist/services/settings-coordinator.js.map +1 -0
  103. package/dist/services/settings-document-repository.d.ts +138 -0
  104. package/dist/services/settings-document-repository.d.ts.map +1 -0
  105. package/dist/services/settings-document-repository.js +551 -0
  106. package/dist/services/settings-document-repository.js.map +1 -0
  107. package/dist/terminal-ui/launch.d.ts.map +1 -1
  108. package/dist/terminal-ui/launch.js +5 -0
  109. package/dist/terminal-ui/launch.js.map +1 -1
  110. package/dist/tui-ui/state.d.ts.map +1 -1
  111. package/dist/tui-ui/state.js +5 -0
  112. package/dist/tui-ui/state.js.map +1 -1
  113. package/dist/web/event-hub.d.ts +39 -0
  114. package/dist/web/event-hub.d.ts.map +1 -0
  115. package/dist/web/event-hub.js +263 -0
  116. package/dist/web/event-hub.js.map +1 -0
  117. package/dist/web/index.d.ts +6 -0
  118. package/dist/web/index.d.ts.map +1 -0
  119. package/dist/web/index.js +28 -0
  120. package/dist/web/index.js.map +1 -0
  121. package/dist/web/launch.d.ts +9 -0
  122. package/dist/web/launch.d.ts.map +1 -0
  123. package/dist/web/launch.js +64 -0
  124. package/dist/web/launch.js.map +1 -0
  125. package/dist/web/protocol.d.ts +346 -0
  126. package/dist/web/protocol.d.ts.map +1 -0
  127. package/dist/web/protocol.js +348 -0
  128. package/dist/web/protocol.js.map +1 -0
  129. package/dist/web/server.d.ts +20 -0
  130. package/dist/web/server.d.ts.map +1 -0
  131. package/dist/web/server.js +498 -0
  132. package/dist/web/server.js.map +1 -0
  133. package/dist/web/workbench-controller.d.ts +63 -0
  134. package/dist/web/workbench-controller.d.ts.map +1 -0
  135. package/dist/web/workbench-controller.js +774 -0
  136. package/dist/web/workbench-controller.js.map +1 -0
  137. package/dist/web-client/assets/index-BAEO71Gp.css +1 -0
  138. package/dist/web-client/assets/index-DSkFy7gM.js +13 -0
  139. package/dist/web-client/index.html +16 -0
  140. package/docs/architecture/v0.3.0-web-api.yaml +1309 -0
  141. package/docs/migration/v0.2.2-to-v0.3.0-settings.md +114 -0
  142. package/docs/migration/v0.2.2-to-v0.3.0.md +55 -0
  143. package/docs/orion.example.json +9 -2
  144. package/docs/plan/v0.3.0-node-runtime-compatibility-plan.md +57 -0
  145. package/docs/plan/v0.3.0-settings-integration-plan.md +740 -0
  146. package/docs/plan/v0.3.0-web-workbench-plan.md +325 -0
  147. package/docs/readme.md +12 -1
  148. package/npm-shrinkwrap.json +1779 -426
  149. package/package.json +33 -9
package/CHANGELOG.md CHANGED
@@ -22,6 +22,46 @@ which is **not** a pass.
22
22
 
23
23
  ## [Unreleased]
24
24
 
25
+ ## [0.3.0] — CANDIDATE
26
+
27
+ > **Status: candidate.** This source version is not a Git tag, GitHub Release or npm publication
28
+ > until those external receipts are created and read back separately.
29
+
30
+ ### Added
31
+
32
+ - Add `orion web`, a loopback-only React workbench for workspace/session navigation, streaming
33
+ conversation and tools, follow-up/interrupt, approvals, Goal/Plan, model/effort settings,
34
+ Skills/MCP metadata, large-output inspection and diagnostics.
35
+ - Add a versioned same-origin Web API with bounded cursor pagination, process-lifetime idempotency
36
+ keys, settings compare-and-swap, session recovery snapshots and a replayable SSE event stream.
37
+ - Add a Host-owned Settings subsystem with strict typed reads, keyed exact-byte revisions,
38
+ raw-preserving atomic batch updates, lock-inside CAS, external-edit convergence, last-good
39
+ recovery and browser conflict handling.
40
+ - Add the source-audited v0.3.0 product plan, OpenAPI contract and v0.2.2 migration/rollback guide.
41
+
42
+ ### Changed
43
+
44
+ - Set the release-qualification contract to maintained Node 22.12+, 24 and 26; publication now
45
+ requires exact-tarball native SQLite, CLI, TUI, Web and fail-closed evidence on every line.
46
+ - Extract the CLI composition into one shared product bootstrap so Web, TUI, terminal and print
47
+ retain the same AgentRuntimeController, OrionSessionRunner, OrionRuntime and durable stores.
48
+ - Resolve new root/child runtimes from the selected model profile and support exact
49
+ BUILD/PLAN/AUTO selection at the next logical-request boundary.
50
+ - Align durable approval scopes with the product permission store as `once`, `project`, `global`.
51
+ - Route Web, TUI and slash-command changes for default model, project/global effort and tool
52
+ confirmation through one Settings coordinator; keep the current-session model distinct from the
53
+ default for newly created sessions.
54
+
55
+ ### Security
56
+
57
+ - Bind Web only to `127.0.0.1`; require exact Origin, per-process nonce and JSON for mutations; cap
58
+ bodies and pages; reject Host/path-boundary violations; and send restrictive browser headers.
59
+ - Keep pending approvals runtime-owned across browser disconnects, redact browser-safe projections,
60
+ expose no provider credentials, and disconnect slow SSE clients so they recover by cursor rather
61
+ than growing an unbounded response buffer.
62
+ - Expose credential readiness only, keep the configuration-file action pathless, preserve invalid
63
+ external bytes, and require Runtime-idle mutation for settings that alter execution policy.
64
+
25
65
  ## [0.2.2] — 2026-08-27
26
66
 
27
67
  > **Status: published.** The `v0.2.2` tag and npm `latest` package identify this release tree.
package/README.md CHANGED
@@ -1,13 +1,37 @@
1
1
  # Orion Code
2
2
 
3
- Goal-driven coding agent for the terminal.
4
-
5
- > v0.2.2resilient Thread session recovery, provider-safe interrupted tool
6
- > history, and width-stable Goal usage visibility on the v0.2 Harness.
7
-
8
- [中文说明](README.zh-CN.md) · [Architecture plan](docs/plan/v0.2.0-dsh-harness-redesign-plan.md) ·
9
- [Migration guide](docs/migration/v0.1.9-to-v0.2.0.md) ·
10
- [Release checklist](docs/plan/v0.2.0-release-checklist.md)
3
+ Local-first, goal-driven coding agent for the terminal and browser.
4
+
5
+ > v0.3.0 candidate one Orion runtime with a local Web Workbench, replayable browser state and
6
+ > the existing TUI/terminal surfaces. Candidate source is not an npm publication or Git tag.
7
+
8
+ [中文说明](README.zh-CN.md) · [v0.3.0 Web plan](docs/plan/v0.3.0-web-workbench-plan.md) ·
9
+ [Settings plan](docs/plan/v0.3.0-settings-integration-plan.md) ·
10
+ [Node compatibility](docs/plan/v0.3.0-node-runtime-compatibility-plan.md) ·
11
+ [Web API](docs/architecture/v0.3.0-web-api.yaml) ·
12
+ [Migration guide](docs/migration/v0.2.2-to-v0.3.0.md) ·
13
+ [Settings migration](docs/migration/v0.2.2-to-v0.3.0-settings.md) ·
14
+ [real-state gallery](docs/assets/screenshots/v0.3.0-web/README.md)
15
+
16
+ ## What changes in v0.3.0
17
+
18
+ - **One runtime, two interactive surfaces.** `orion web` uses the same product bootstrap,
19
+ AgentRuntimeController, Session/Thread stores, ToolGateway, approvals, Goals, Plans, Skills and
20
+ MCP boundaries as the terminal product; the browser does not run a second agent loop.
21
+ - **Recoverable Web workbench.** The React workbench includes workspace/session navigation,
22
+ transcript and tool activity, BUILD/PLAN/AUTO, follow-ups, interrupt, approvals, Goal/Plan,
23
+ model/effort settings, Skills/MCP and diagnostics. Snapshots plus cursor replay repair refreshes
24
+ and SSE reconnects.
25
+ - **Local security boundary.** The host binds only `127.0.0.1`; writes require an exact Origin,
26
+ process nonce, JSON body and idempotency key. Responses use a restrictive CSP, browser payloads
27
+ are redacted, and large tool results are byte-paged instead of placed on the event stream.
28
+ - **Host-owned Settings.** Appearance, the default model, workspace effort and the global tool
29
+ confirmation policy use one strict, revisioned `orion.json` coordinator. Atomic batches, file-lock
30
+ CAS, external-edit invalidation, last-good recovery and explicit source/scope/apply metadata keep
31
+ the browser, slash commands, TUI and Runtime on the same persisted truth.
32
+ - **Deliberate DSH adaptation.** The design was source-audited against a fixed DeepSeek Harness
33
+ revision. DSH's browser uses POST plus two downlink WebSockets; Orion intentionally uses JSON
34
+ HTTP plus one replayable SSE downlink while retaining Orion's Model/Skills/MCP boundaries.
11
35
 
12
36
  ## What changed in v0.2.0
13
37
 
@@ -44,12 +68,13 @@ user extension boundaries.
44
68
 
45
69
  ## Install
46
70
 
47
- Node.js 20, 22, and 24 are supported.
71
+ Node.js 22.12+, 24, and 26 are supported. Use Node 24 LTS for production or Node 26 Current for
72
+ current development environments. Node 20 is upstream EOL and is no longer a v0.3 runtime.
48
73
 
49
- Install the published `0.2.2` release:
74
+ After the immutable `0.3.0` npm receipt exists:
50
75
 
51
76
  ```bash
52
- npm install -g @orion-agents/orion-code@0.2.2
77
+ npm install -g @orion-agents/orion-code@0.3.0
53
78
  orion --version
54
79
  orion doctor
55
80
  ```
@@ -106,6 +131,9 @@ Run `orion doctor` after configuration. Diagnostics never need to print the secr
106
131
  ```bash
107
132
  orion # default product TUI
108
133
  orion --ui terminal # technical terminal fallback
134
+ orion web # local Web Workbench; opens a browser
135
+ orion web --no-open --port 0 # choose an ephemeral loopback port
136
+ orion web --cwd /path/to/repo # start against another existing workspace
109
137
  orion -p "explain this repo" # experimental non-interactive mode
110
138
  orion -p --output-format json "run the focused tests"
111
139
  orion diff
@@ -115,6 +143,35 @@ orion commit
115
143
  Experimental non-interactive print mode is available through `orion -p`; keep it out of
116
144
  interactive workflows that require confirmations or live steering.
117
145
 
146
+ ### Local Web Workbench
147
+
148
+ `orion web` serves the packaged client and `/api/v1/*` from one loopback origin. It does not expose
149
+ a LAN bind. Configure provider credentials with the normal Orion config/environment flow, then use
150
+ the browser to select a workspace and session, run or steer work, answer approvals, and inspect
151
+ runtime state. Closing or refreshing a tab leaves pending approvals owned by the runtime; stopping
152
+ the host aborts them fail-closed.
153
+
154
+ The browser exposes Plan receipts exactly as committed (`body`, `returnMode`, `digest`). It does not
155
+ insert an extra review gate: after PLAN commits, the existing runtime restores BUILD/AUTO and starts
156
+ implementation in a separate logical turn.
157
+
158
+ #### Host-managed Settings
159
+
160
+ The Settings dialog reads from the active Host rather than treating browser storage as a second
161
+ configuration source. Theme and reduced-motion preferences persist across refreshes, ports and Host
162
+ restarts. The default model applies to newly created sessions; changing the current session remains
163
+ an explicit `/model` or session-control action. Effort is the active workspace's project default,
164
+ with a session override taking precedence. Tool confirmation is global, may be changed only while
165
+ the Runtime is idle and applies at the next logical request; `allow` never bypasses hard policy,
166
+ sandbox or workspace containment.
167
+
168
+ Every save is one atomic compare-and-swap batch. A concurrent tab or external `orion.json` edit is
169
+ shown as a conflict without discarding the draft. Invalid external JSON preserves the last-good
170
+ Runtime configuration and is never overwritten by the Web UI. Provider credentials remain outside
171
+ the Web API: Settings exposes readiness only and its local configuration action accepts no path.
172
+ See the [Settings migration guide](docs/migration/v0.2.2-to-v0.3.0-settings.md) for precedence,
173
+ legacy appearance import and rollback details.
174
+
118
175
  ### BUILD, PLAN, AUTO
119
176
 
120
177
  Press `Shift+Tab` to cycle `BUILD → PLAN → AUTO`. The status bar and input border show the current
@@ -190,12 +247,14 @@ npm run bench:harness:baseline
190
247
  npm run bench:harness
191
248
  npm run bench:harness:compare -- <baseline.json> <candidate.json>
192
249
  npm run prepublishOnly
250
+ npm run test:web-e2e -- --grep @settings
193
251
  ```
194
252
 
195
253
  Release qualification additionally builds one exact tarball and installs that unchanged hash on
196
- Node 20/22/24 for package identity, native SQLite, TUI, terminal, print, Goal, subagent, Skill, MCP,
197
- Compact, and resume journeys. See the
198
- [`v0.2.0 release checklist`](docs/plan/v0.2.0-release-checklist.md).
254
+ Node 22/24/26 for package identity, native SQLite, TUI, terminal, print, Web, Goal, subagent, Skill,
255
+ MCP, Compact, and resume journeys. See the
256
+ [`v0.3.0 Web Workbench plan`](docs/plan/v0.3.0-web-workbench-plan.md) and
257
+ [`v0.3.0 Settings integration plan`](docs/plan/v0.3.0-settings-integration-plan.md).
199
258
 
200
259
  ## Security
201
260
 
package/README.zh-CN.md CHANGED
@@ -1,13 +1,34 @@
1
1
  # Orion Code
2
2
 
3
- 面向终端的目标驱动 Coding Agent。
4
-
5
- > v0.2.2:让 Thread 会话恢复具备单会话故障隔离,安全恢复中断的工具历史,并确保窄终端
6
- > 始终可见 Goal 已用 token
7
-
8
- [English](README.md) · [架构主计划](docs/plan/v0.2.0-dsh-harness-redesign-plan.md) ·
9
- [迁移指南](docs/migration/v0.1.9-to-v0.2.0.md) ·
10
- [准出清单](docs/plan/v0.2.0-release-checklist.md)
3
+ 面向终端与浏览器、本地优先的目标驱动 Coding Agent。
4
+
5
+ > v0.3.0 候选版本:一套 Orion Runtime,同时提供本地 Web Workbench 与既有 TUI/terminal。
6
+ > Candidate 源码不代表已经创建 npm 发布或 Git tag
7
+
8
+ [English](README.md) · [v0.3.0 Web 方案](docs/plan/v0.3.0-web-workbench-plan.md) ·
9
+ [Settings 方案](docs/plan/v0.3.0-settings-integration-plan.md) ·
10
+ [Node 兼容方案](docs/plan/v0.3.0-node-runtime-compatibility-plan.md) ·
11
+ [Web API](docs/architecture/v0.3.0-web-api.yaml) ·
12
+ [迁移指南](docs/migration/v0.2.2-to-v0.3.0.md) ·
13
+ [Settings 迁移](docs/migration/v0.2.2-to-v0.3.0-settings.md) ·
14
+ [真实状态图册](docs/assets/screenshots/v0.3.0-web/README.md)
15
+
16
+ ## v0.3.0 将带来什么
17
+
18
+ - **一个 Runtime、两个交互界面。** `orion web` 与终端产品共用 product bootstrap、
19
+ AgentRuntimeController、Session/Thread、ToolGateway、审批、Goal、Plan、Skills 和 MCP;浏览器不另起
20
+ 一套 agent loop。
21
+ - **可恢复的 Web 工作台。** React 界面覆盖工作区/会话、对话与工具活动、BUILD/PLAN/AUTO、follow-up、
22
+ interrupt、审批、Goal/Plan、模型/effort、Skills/MCP 和诊断。快照与 cursor replay 负责刷新和 SSE
23
+ 重连恢复。
24
+ - **本地安全边界。** Host 只绑定 `127.0.0.1`;写请求必须携带精确 Origin、进程 nonce、JSON body 和
25
+ 幂等键。响应设置严格 CSP,浏览器 payload 经过脱敏,大型工具结果按字节分页读取。
26
+ - **Host 管理的 Settings。** 外观、默认模型、工作区 Effort 与全局工具确认策略统一进入严格、带
27
+ revision 的 `orion.json` Coordinator。原子批量保存、文件锁内 CAS、外部编辑 invalidation、
28
+ last-good 恢复与明确的来源/作用域/生效时机,让浏览器、slash 命令、TUI 与 Runtime 使用同一持久真相。
29
+ - **有边界地参考 DSH。** 方案基于固定 DeepSeek Harness revision 做了源码审计。DSH Web 实际使用
30
+ POST 加两条下行 WebSocket;Orion 有意选择 JSON HTTP 加一条可 replay 的 SSE,同时保留 Orion 的
31
+ Model/Skills/MCP 边界。
11
32
 
12
33
  ## v0.2.0 带来了什么
13
34
 
@@ -39,12 +60,13 @@ MCP 仍是用户可见的扩展边界。
39
60
 
40
61
  ## 安装
41
62
 
42
- 支持 Node.js 20、2224
63
+ 支持 Node.js 22.12+、24 和 26。生产环境建议使用 Node 24 LTS,当前开发环境也支持 Node 26
64
+ Current。Node 20 已结束上游维护,不再属于 v0.3 Runtime 合同。
43
65
 
44
- 安装已发布的 `0.2.2` 版本:
66
+ npm 已存在不可变的 `0.3.0` 发布凭据后:
45
67
 
46
68
  ```bash
47
- npm install -g @orion-agents/orion-code@0.2.2
69
+ npm install -g @orion-agents/orion-code@0.3.0
48
70
  orion --version
49
71
  orion doctor
50
72
  ```
@@ -101,6 +123,9 @@ Orion 读取 `~/.orion-code/orion.json`。可从
101
123
  ```bash
102
124
  orion # 默认产品 TUI
103
125
  orion --ui terminal # 技术诊断 terminal fallback
126
+ orion web # 启动本地 Web Workbench 并打开浏览器
127
+ orion web --no-open --port 0 # 使用操作系统分配的 loopback 端口
128
+ orion web --cwd /path/to/repo # 指定另一个已存在工作区
104
129
  orion -p "解释这个仓库" # 实验性的非交互模式
105
130
  orion -p --output-format json "运行 focused tests"
106
131
  orion diff
@@ -109,6 +134,28 @@ orion commit
109
134
 
110
135
  `orion -p` 是早期实验性的非交互入口;需要确认弹层或实时 steering 的任务应使用 TUI。
111
136
 
137
+ ### 本地 Web Workbench
138
+
139
+ `orion web` 在同一个 loopback origin 提供打包后的客户端与 `/api/v1/*`,v0.3.0 不提供 LAN bind。
140
+ Provider 凭据仍通过 Orion 配置/环境变量管理;浏览器负责选择工作区和会话、执行或 steer 任务、回答
141
+ 审批并查看运行态。关闭或刷新 tab 不会替用户批准/拒绝,pending approval 仍由 Runtime 持有;停止
142
+ Host 时会 abort 并 fail-closed。
143
+
144
+ 浏览器只展示已提交 Plan receipt 的 `body`、`returnMode`、`digest`,不会额外插入 review gate。
145
+ PLAN 提交后仍由既有 Runtime 恢复 BUILD/AUTO,并在新的 logical turn 中启动实现。
146
+
147
+ #### Host 管理的 Settings
148
+
149
+ Settings dialog 从当前 Host 读取设置,不把浏览器存储当成第二配置真源。主题和减少动效会跨刷新、端口
150
+ 和 Host 重启保留;默认模型只影响新建 Session,当前 Session 仍通过 `/model` 或会话控制显式切换;
151
+ Effort 是当前 workspace 的 project default,Session override 优先;工具确认是全局策略,只能在 Runtime
152
+ idle 时保存,并从下一个 logical request 生效。`allow` 不会绕过 hard policy、sandbox 或工作区边界。
153
+
154
+ 每次保存都是一次原子 CAS batch。并发标签页或外部 `orion.json` 编辑会显示冲突但保留草稿;非法 JSON
155
+ 只会让页面进入 invalid 状态,Runtime 继续使用 last-good,Web 绝不覆盖坏文件。Provider 凭据不会进入
156
+ Web API,页面只显示 readiness,打开本地配置文件的动作也不接受 path。优先级、旧 appearance 一次迁移
157
+ 和回滚方法见 [Settings 迁移说明](docs/migration/v0.2.2-to-v0.3.0-settings.md)。
158
+
112
159
  ### BUILD、PLAN、AUTO
113
160
 
114
161
  按 `Shift+Tab` 循环 `BUILD → PLAN → AUTO`。状态栏和输入框边框会显示当前模式。Mode 决定工作流,
@@ -179,11 +226,13 @@ npm run bench:harness:baseline
179
226
  npm run bench:harness
180
227
  npm run bench:harness:compare -- <baseline.json> <candidate.json>
181
228
  npm run prepublishOnly
229
+ npm run test:web-e2e -- --grep @settings
182
230
  ```
183
231
 
184
- 正式准出还会只构建一次 exact tarball,并在 Node 20/22/24 安装同一个 hash,验证 package identity、
185
- native SQLite、TUI、terminal、print、Goal、subagent、Skill、MCP、Compact 与 resume。详见
186
- [`v0.2.0 准出清单`](docs/plan/v0.2.0-release-checklist.md)
232
+ 正式准出还会只构建一次 exact tarball,并在 Node 22/24/26 安装同一个 hash,验证 package identity、
233
+ native SQLite、TUI、terminal、print、Web、Goal、subagent、Skill、MCP、Compact 与 resume。详见
234
+ [`v0.3.0 Web Workbench 方案`](docs/plan/v0.3.0-web-workbench-plan.md)
235
+ [`v0.3.0 Settings 集成方案`](docs/plan/v0.3.0-settings-integration-plan.md)。
187
236
 
188
237
  ## 安全
189
238
 
package/bin/orion CHANGED
@@ -4,6 +4,16 @@ const path = require('path');
4
4
  const os = require('os');
5
5
  const fs = require('fs');
6
6
 
7
+ const [nodeMajor, nodeMinor] = process.versions.node.split('.').map(Number);
8
+ const supportedNodeRuntime =
9
+ (nodeMajor === 22 && nodeMinor >= 12) || nodeMajor === 24 || nodeMajor === 26;
10
+ if (!supportedNodeRuntime) {
11
+ console.error(
12
+ `Orion Code requires Node.js 22.12+, 24, or 26; current runtime is ${process.versions.node}.`
13
+ );
14
+ process.exit(1);
15
+ }
16
+
7
17
  // ============================================================================
8
18
  // Multi-path .env loading
9
19
  //
@@ -22,22 +32,23 @@ function loadEnvFile(filePath) {
22
32
  }
23
33
 
24
34
  const envFilesLoaded = [];
35
+ const loadConfiguredEnvFiles = process.env.ORION_CODE_DISABLE_ENV_FILES !== '1';
25
36
 
26
37
  // 1. Global config: ~/.orion-code.env
27
38
  const globalEnv = path.join(os.homedir(), '.orion-code.env');
28
- if (loadEnvFile(globalEnv)) {
39
+ if (loadConfiguredEnvFiles && loadEnvFile(globalEnv)) {
29
40
  envFilesLoaded.push(globalEnv);
30
41
  }
31
42
 
32
43
  // 2. Current working directory: ./.env
33
44
  const localEnv = path.join(process.cwd(), '.env');
34
- if (loadEnvFile(localEnv)) {
45
+ if (loadConfiguredEnvFiles && loadEnvFile(localEnv)) {
35
46
  envFilesLoaded.push(localEnv);
36
47
  }
37
48
 
38
49
  // 3. Package directory (development fallback)
39
50
  const packageEnv = path.join(__dirname, '..', '.env');
40
- if (loadEnvFile(packageEnv)) {
51
+ if (loadConfiguredEnvFiles && loadEnvFile(packageEnv)) {
41
52
  envFilesLoaded.push(packageEnv);
42
53
  }
43
54
 
@@ -53,4 +64,4 @@ if (fs.existsSync(distCli)) {
53
64
  } else {
54
65
  require('ts-node').register({ transpileOnly: true });
55
66
  require(srcCli);
56
- }
67
+ }
package/dist/cli.js CHANGED
@@ -7,32 +7,17 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
7
7
  };
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  const chalk_1 = __importDefault(require("chalk"));
10
- const llm_1 = require("./services/llm");
11
- const provider_resilience_1 = require("./services/provider-resilience");
12
- const model_coordinator_1 = require("./runtime/model-coordinator");
13
10
  const config_1 = require("./services/config");
14
- const config_dir_1 = require("./services/config-dir");
15
- const global_config_1 = require("./services/global-config");
16
- const usage_state_1 = require("./services/usage-state");
17
- const session_storage_1 = require("./services/session-storage");
18
- const prompt_context_1 = require("./memory/prompt-context");
19
- const project_instructions_1 = require("./services/project-instructions");
20
- const store_1 = require("./framework/store");
21
- const model_context_1 = require("./services/model-context");
22
11
  const launch_1 = require("./tui-ui/launch");
23
12
  const launch_2 = require("./terminal-ui/launch");
24
13
  const launch_3 = require("./print-ui/launch");
25
14
  const doctor_1 = require("./services/doctor");
26
15
  const workspace_diff_1 = require("./services/workspace-diff");
27
16
  const commit_plan_1 = require("./services/commit-plan");
28
- const first_party_tool_universe_1 = require("./runtime/first-party-tool-universe");
29
- const product_orion_runtime_1 = require("./runtime/product-orion-runtime");
30
- const mcp_1 = require("./runtime/mcp");
31
- const skills_1 = require("./runtime/skills");
32
- const orion_session_runner_1 = require("./runtime/orion-session-runner");
33
- const compact_1 = require("./services/compact");
17
+ const product_bootstrap_1 = require("./runtime/product-bootstrap");
34
18
  const command_1 = require("./migration/command");
35
19
  const version_1 = require("./product/version");
20
+ const web_1 = require("./web");
36
21
  const BRAND = chalk_1.default.hex('#FF6B35');
37
22
  const ACCENT = chalk_1.default.hex('#00D4AA');
38
23
  const DIM = chalk_1.default.dim;
@@ -50,6 +35,7 @@ function showCliHelp() {
50
35
  console.log(' orion diff Summarize current git workspace changes');
51
36
  console.log(' orion commit Create a read-only commit plan and suggested message');
52
37
  console.log(' orion migrate openhorse Preview OpenHorse migration; add --yes to execute');
38
+ console.log(' orion web Start the local Web Workbench');
53
39
  console.log(' orion -p "task" Run an experimental non-interactive task');
54
40
  console.log(' orion --help Show this help message');
55
41
  console.log(' orion --version Show version');
@@ -66,6 +52,42 @@ function showCliHelp() {
66
52
  console.log(DIM('tui is the default product UI. terminal is the technical fallback; print is experimental.'));
67
53
  console.log();
68
54
  }
55
+ function parseWebCliOptions(args) {
56
+ let port = 3080;
57
+ let open = true;
58
+ let cwd = process.cwd();
59
+ for (let index = 0; index < args.length; index++) {
60
+ const argument = args[index];
61
+ if (argument === '--no-open') {
62
+ open = false;
63
+ continue;
64
+ }
65
+ if (argument === '--port' || argument.startsWith('--port=')) {
66
+ const portValue = argument === '--port' ? args[++index] : argument.slice('--port='.length);
67
+ if (!portValue || !/^\d+$/u.test(portValue)) {
68
+ throw new Error('--port must be an integer from 0 through 65535.');
69
+ }
70
+ port = Number(portValue);
71
+ if (!Number.isSafeInteger(port) || port < 0 || port > 65535) {
72
+ throw new Error('--port must be an integer from 0 through 65535.');
73
+ }
74
+ continue;
75
+ }
76
+ if (argument === '--cwd' || argument.startsWith('--cwd=')) {
77
+ const cwdValue = argument === '--cwd' ? args[++index] : argument.slice('--cwd='.length);
78
+ if (!cwdValue?.trim())
79
+ throw new Error('--cwd requires a directory path.');
80
+ cwd = cwdValue;
81
+ continue;
82
+ }
83
+ throw new Error(`Unknown orion web option: ${argument}`);
84
+ }
85
+ return { port, open, cwd };
86
+ }
87
+ function showWebHelp() {
88
+ console.log('Usage: orion web [--port <number>] [--no-open] [--cwd <directory>]');
89
+ console.log('Starts the local-only Web Workbench on 127.0.0.1.');
90
+ }
69
91
  function parseCliOptions(args) {
70
92
  let uiRenderer = config_1.DEFAULT_UI_RENDERER;
71
93
  let printMode = false;
@@ -124,165 +146,22 @@ function parseCliOptions(args) {
124
146
  return { uiRenderer, printMode, outputFormat, promptArgs };
125
147
  }
126
148
  async function bootstrapRuntime(uiRenderer) {
127
- (0, config_dir_1.ensureConfigDir)();
128
- (0, global_config_1.recordFirstStartTime)();
129
- const cwd = process.cwd();
130
- const config = (0, config_1.loadConfig)({ ui: { renderer: uiRenderer } });
131
- const memoryContent = (0, prompt_context_1.buildMemoryPromptContext)('', cwd).content;
132
- const projectInstructionsContent = (0, project_instructions_1.loadProjectInstructions)(cwd);
133
- const firstPartyTools = (0, first_party_tool_universe_1.createProductionFirstPartyToolUniverseV1)({
134
- context: { cwd, config: { name: config.name, mode: config.mode } },
135
- });
136
- const toolCatalog = firstPartyTools.catalog;
137
- const skillProvider = (0, skills_1.createProductionFilesystemSkillProviderV1)({
138
- cwd,
139
- configuredPaths: config.skills?.paths,
149
+ return (0, product_bootstrap_1.createProductUiRuntime)({
150
+ cwd: process.cwd(),
151
+ uiRenderer,
152
+ shutdownReason: 'Orion CLI shutdown',
140
153
  });
141
- const mcpAdapter = (0, mcp_1.createFirstPartyMcpAdapterV1)({
142
- config: (0, mcp_1.loadFirstPartyMcpConfigurationV1)(),
143
- baseDirectory: cwd,
144
- });
145
- const store = new store_1.Store({
146
- config,
147
- tools: toolCatalog.entries.map(entry => entry.tool),
148
- currentModel: config.model,
149
- memoryContent,
150
- // Skill descriptors/definitions are selected by the lazy v0.2.0 runtime.
151
- // The presentation Store must never eagerly retain Skill bodies.
152
- skillsContent: '',
153
- projectInstructionsContent,
154
- });
155
- let llm = null;
156
- let modelCoordinator;
157
- // Resolve credentials from the configured model registry or legacy config.
158
- const configured = config.modelRegistry
159
- ? config.modelRegistry.defaultProfile !== null
160
- : (0, config_1.isConfigured)(config);
161
- if (configured) {
162
- const defaultProvider = config.modelRegistry?.defaultProfile
163
- ? config.modelRegistry.providers.get(config.modelRegistry.defaultProfile.provider)
164
- : null;
165
- llm = new llm_1.LLMService({
166
- apiKey: defaultProvider
167
- ? defaultProvider.apiKey.startsWith('$')
168
- ? (process.env[defaultProvider.apiKey.slice(1)] ?? '')
169
- : defaultProvider.apiKey
170
- : config.apiKey,
171
- baseUrl: defaultProvider?.baseUrl ?? config.apiBaseUrl,
172
- model: config.modelRegistry?.defaultProfile?.model ?? config.model,
173
- fallbackModel: config.modelRegistry?.fallbackProfile?.model ?? config.fallbackModel,
174
- providerProtocol: defaultProvider?.protocol,
175
- reasoningCapability: config.modelRegistry?.defaultProfile?.reasoningCapability,
176
- fallbackReasoningCapability: config.modelRegistry?.fallbackProfile?.reasoningCapability,
177
- effortPreference: config.defaultEffort,
178
- });
179
- // Keep chat() and chatStream() on the shared provider-resilience layer.
180
- llm.resilience = new provider_resilience_1.ProviderResilienceCoordinator();
181
- // Initialize ModelCoordinator for /model switching.
182
- modelCoordinator = new model_coordinator_1.ModelCoordinator();
183
- if (config.modelRegistry && config.modelClientPool) {
184
- modelCoordinator.bind(config.modelRegistry, config.modelClientPool);
185
- modelCoordinator.initModel(config.model);
186
- }
187
- if (config.apiBaseUrl) {
188
- (0, model_context_1.discoverModelContexts)(config.apiBaseUrl, config.apiKey).catch(() => undefined);
189
- }
190
- }
191
- const compactCoordinator = new compact_1.CompactCoordinator({
192
- modelId: llm?.getModel() ?? config.model,
193
- llm,
194
- outputReserveTokens: llm?.getMaxTokens?.(),
195
- compactInstructions: (0, global_config_1.getProjectConfig)(cwd).compactInstructions,
196
- getContextCapsule: () => store.getSnapshot().harnessState?.capsule,
197
- getHarnessState: () => store.getSnapshot().harnessState,
198
- });
199
- let currentSession = null;
200
- let sessionRunner;
201
- let shuttingDown = false;
202
- const ensureSession = () => {
203
- if (!currentSession) {
204
- currentSession = (0, session_storage_1.createSession)(cwd, store.getSnapshot().currentModel || store.getSnapshot().config.model);
205
- (0, global_config_1.incrementSessionCount)();
206
- }
207
- return currentSession;
208
- };
209
- const setSession = (session) => {
210
- currentSession = session;
211
- };
212
- const getSession = () => currentSession;
213
- const costTracker = store.getSnapshot().costTracker;
214
- costTracker.setRecordSink(record => {
215
- (0, usage_state_1.appendUsageRecord)(record, {
216
- sessionId: currentSession?.id,
217
- projectPath: cwd,
218
- });
219
- });
220
- const unsubscribeLlmUsage = llm?.subscribeUsage(event => {
221
- costTracker.record(event.usage, {
222
- model: event.model,
223
- requestKind: event.operation,
224
- });
225
- });
226
- const shutdown = async () => {
227
- if (shuttingDown)
228
- return;
229
- shuttingDown = true;
230
- await sessionRunner?.close('Orion CLI shutdown');
231
- if (currentSession) {
232
- const messages = (0, session_storage_1.readSessionMessages)(currentSession.id);
233
- if (messages.length > 0) {
234
- (0, session_storage_1.updateSessionSummary)(currentSession.id, messages);
235
- }
236
- (0, session_storage_1.endSession)(currentSession.id);
237
- }
238
- unsubscribeLlmUsage?.();
239
- };
240
- const createAgentRunner = llm
241
- ? (events, runnerOptions) => {
242
- if (sessionRunner)
243
- return sessionRunner;
244
- sessionRunner = new orion_session_runner_1.OrionSessionRunnerV1({
245
- eventSink: events,
246
- getSessionId: () => ensureSession().id,
247
- createRuntime: sessionId => (0, product_orion_runtime_1.createProductOrionRuntimeV1)({
248
- cwd,
249
- config,
250
- store,
251
- llm: llm,
252
- compactCoordinator,
253
- toolCatalog,
254
- skillProviders: [skillProvider],
255
- mcpDescriptors: mcpAdapter.descriptors,
256
- mcpConnector: mcpAdapter.connector,
257
- approvalHandler: runnerOptions.approvalHandler,
258
- }, sessionId),
259
- mode: () => {
260
- const mode = store.getSnapshot().agentMode;
261
- return mode === 'plan' ? 'plan' : mode === 'auto' ? 'auto' : 'build';
262
- },
263
- });
264
- return sessionRunner;
265
- }
266
- : undefined;
267
- return {
268
- cwd,
269
- version: VERSION,
270
- config,
271
- store,
272
- llm,
273
- compactCoordinator,
274
- modelCoordinator,
275
- createAgentRunner,
276
- getHarnessDiagnostics: async () => sessionRunner?.diagnostics(),
277
- isConfigured: (0, config_1.isConfigured)(config),
278
- ensureSession,
279
- setSession,
280
- getSession,
281
- shutdown,
282
- };
283
154
  }
284
155
  async function main() {
285
156
  const args = process.argv.slice(2);
157
+ if (args[0] === 'web') {
158
+ if (args.includes('--help') || args.includes('-h')) {
159
+ showWebHelp();
160
+ return;
161
+ }
162
+ await (0, web_1.runOrionWeb)(parseWebCliOptions(args.slice(1)));
163
+ return;
164
+ }
286
165
  if (args[0] === 'migrate') {
287
166
  const result = (0, command_1.handleMigrateCommand)({ cwd: process.cwd() }, args.slice(1).join(' '));
288
167
  process.exit(result.success ? 0 : 1);