@orion-agents/orion-code 0.2.2 → 0.3.1

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 (217) hide show
  1. package/CHANGELOG.md +82 -0
  2. package/README.md +89 -14
  3. package/README.zh-CN.md +77 -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/core/tool-artifacts.d.ts +2 -0
  19. package/dist/core/tool-artifacts.d.ts.map +1 -1
  20. package/dist/core/tool-artifacts.js +27 -1
  21. package/dist/core/tool-artifacts.js.map +1 -1
  22. package/dist/index.d.ts +1 -1
  23. package/dist/index.js +1 -1
  24. package/dist/runtime/agent-loop.d.ts.map +1 -1
  25. package/dist/runtime/agent-loop.js +3 -3
  26. package/dist/runtime/agent-loop.js.map +1 -1
  27. package/dist/runtime/agent-runtime-controller.d.ts +32 -1
  28. package/dist/runtime/agent-runtime-controller.d.ts.map +1 -1
  29. package/dist/runtime/agent-runtime-controller.js +241 -27
  30. package/dist/runtime/agent-runtime-controller.js.map +1 -1
  31. package/dist/runtime/agent-runtime-protocol.d.ts +4 -0
  32. package/dist/runtime/agent-runtime-protocol.d.ts.map +1 -1
  33. package/dist/runtime/agent-runtime-protocol.js.map +1 -1
  34. package/dist/runtime/agent-runtime-runner.d.ts +2 -1
  35. package/dist/runtime/agent-runtime-runner.d.ts.map +1 -1
  36. package/dist/runtime/durable-tool-receipt-reader.d.ts +32 -0
  37. package/dist/runtime/durable-tool-receipt-reader.d.ts.map +1 -0
  38. package/dist/runtime/durable-tool-receipt-reader.js +130 -0
  39. package/dist/runtime/durable-tool-receipt-reader.js.map +1 -0
  40. package/dist/runtime/legacy-thread-materializer.d.ts +31 -0
  41. package/dist/runtime/legacy-thread-materializer.d.ts.map +1 -1
  42. package/dist/runtime/legacy-thread-materializer.js +71 -17
  43. package/dist/runtime/legacy-thread-materializer.js.map +1 -1
  44. package/dist/runtime/orion-runtime-v1.d.ts +2 -0
  45. package/dist/runtime/orion-runtime-v1.d.ts.map +1 -1
  46. package/dist/runtime/orion-runtime-v1.js +7 -1
  47. package/dist/runtime/orion-runtime-v1.js.map +1 -1
  48. package/dist/runtime/orion-session-runner.d.ts +7 -2
  49. package/dist/runtime/orion-session-runner.d.ts.map +1 -1
  50. package/dist/runtime/orion-session-runner.js +16 -6
  51. package/dist/runtime/orion-session-runner.js.map +1 -1
  52. package/dist/runtime/product-bootstrap.d.ts +22 -0
  53. package/dist/runtime/product-bootstrap.d.ts.map +1 -0
  54. package/dist/runtime/product-bootstrap.js +374 -0
  55. package/dist/runtime/product-bootstrap.js.map +1 -0
  56. package/dist/runtime/product-orion-runtime.d.ts +2 -1
  57. package/dist/runtime/product-orion-runtime.d.ts.map +1 -1
  58. package/dist/runtime/product-orion-runtime.js +83 -13
  59. package/dist/runtime/product-orion-runtime.js.map +1 -1
  60. package/dist/runtime/protocol/runtime-protocol-v1.d.ts +1 -1
  61. package/dist/runtime/protocol/runtime-protocol-v1.js +1 -1
  62. package/dist/runtime/protocol/runtime-protocol-v1.js.map +1 -1
  63. package/dist/runtime/release-receipts.d.ts +66 -3
  64. package/dist/runtime/release-receipts.d.ts.map +1 -1
  65. package/dist/runtime/release-receipts.js +340 -7
  66. package/dist/runtime/release-receipts.js.map +1 -1
  67. package/dist/runtime/step-snapshot.d.ts.map +1 -1
  68. package/dist/runtime/step-snapshot.js +22 -2
  69. package/dist/runtime/step-snapshot.js.map +1 -1
  70. package/dist/runtime/subagents/runtime-integration.d.ts +1 -1
  71. package/dist/runtime/subagents/runtime-integration.d.ts.map +1 -1
  72. package/dist/runtime/subagents/runtime-integration.js +5 -2
  73. package/dist/runtime/subagents/runtime-integration.js.map +1 -1
  74. package/dist/runtime/thread-event-store.d.ts +80 -0
  75. package/dist/runtime/thread-event-store.d.ts.map +1 -1
  76. package/dist/runtime/thread-event-store.js +456 -22
  77. package/dist/runtime/thread-event-store.js.map +1 -1
  78. package/dist/runtime/thread-projection.d.ts +10 -0
  79. package/dist/runtime/thread-projection.d.ts.map +1 -1
  80. package/dist/runtime/thread-projection.js +40 -0
  81. package/dist/runtime/thread-projection.js.map +1 -1
  82. package/dist/runtime/thread-runtime.d.ts +3 -1
  83. package/dist/runtime/thread-runtime.d.ts.map +1 -1
  84. package/dist/runtime/thread-runtime.js +6 -0
  85. package/dist/runtime/thread-runtime.js.map +1 -1
  86. package/dist/runtime/thread-session-index.d.ts +84 -0
  87. package/dist/runtime/thread-session-index.d.ts.map +1 -0
  88. package/dist/runtime/thread-session-index.js +503 -0
  89. package/dist/runtime/thread-session-index.js.map +1 -0
  90. package/dist/runtime/thread-session-view.d.ts +70 -9
  91. package/dist/runtime/thread-session-view.d.ts.map +1 -1
  92. package/dist/runtime/thread-session-view.js +200 -82
  93. package/dist/runtime/thread-session-view.js.map +1 -1
  94. package/dist/runtime/thread-ui-adapter.d.ts +2 -0
  95. package/dist/runtime/thread-ui-adapter.d.ts.map +1 -1
  96. package/dist/runtime/thread-ui-adapter.js +86 -4
  97. package/dist/runtime/thread-ui-adapter.js.map +1 -1
  98. package/dist/runtime/tool-detail-repository.d.ts.map +1 -1
  99. package/dist/runtime/tool-detail-repository.js +23 -19
  100. package/dist/runtime/tool-detail-repository.js.map +1 -1
  101. package/dist/runtime/tool-receipt-validator.d.ts +21 -0
  102. package/dist/runtime/tool-receipt-validator.d.ts.map +1 -0
  103. package/dist/runtime/tool-receipt-validator.js +157 -0
  104. package/dist/runtime/tool-receipt-validator.js.map +1 -0
  105. package/dist/runtime/ui-events.d.ts +35 -0
  106. package/dist/runtime/ui-events.d.ts.map +1 -1
  107. package/dist/runtime/ui-events.js +1 -0
  108. package/dist/runtime/ui-events.js.map +1 -1
  109. package/dist/runtime/ui-view-model.d.ts +2 -0
  110. package/dist/runtime/ui-view-model.d.ts.map +1 -1
  111. package/dist/runtime/ui-view-model.js +7 -3
  112. package/dist/runtime/ui-view-model.js.map +1 -1
  113. package/dist/services/global-config.d.ts +25 -0
  114. package/dist/services/global-config.d.ts.map +1 -1
  115. package/dist/services/global-config.js +373 -5
  116. package/dist/services/global-config.js.map +1 -1
  117. package/dist/services/redaction.d.ts +4 -0
  118. package/dist/services/redaction.d.ts.map +1 -1
  119. package/dist/services/redaction.js +63 -0
  120. package/dist/services/redaction.js.map +1 -1
  121. package/dist/services/session-index.d.ts +16 -0
  122. package/dist/services/session-index.d.ts.map +1 -1
  123. package/dist/services/session-index.js +45 -36
  124. package/dist/services/session-index.js.map +1 -1
  125. package/dist/services/session-storage.d.ts +59 -0
  126. package/dist/services/session-storage.d.ts.map +1 -1
  127. package/dist/services/session-storage.js +306 -107
  128. package/dist/services/session-storage.js.map +1 -1
  129. package/dist/services/settings-coordinator.d.ts +174 -0
  130. package/dist/services/settings-coordinator.d.ts.map +1 -0
  131. package/dist/services/settings-coordinator.js +605 -0
  132. package/dist/services/settings-coordinator.js.map +1 -0
  133. package/dist/services/settings-document-repository.d.ts +138 -0
  134. package/dist/services/settings-document-repository.d.ts.map +1 -0
  135. package/dist/services/settings-document-repository.js +551 -0
  136. package/dist/services/settings-document-repository.js.map +1 -0
  137. package/dist/services/workspace-registry.d.ts +42 -0
  138. package/dist/services/workspace-registry.d.ts.map +1 -0
  139. package/dist/services/workspace-registry.js +222 -0
  140. package/dist/services/workspace-registry.js.map +1 -0
  141. package/dist/terminal-ui/launch.d.ts.map +1 -1
  142. package/dist/terminal-ui/launch.js +5 -0
  143. package/dist/terminal-ui/launch.js.map +1 -1
  144. package/dist/tui-ui/state.d.ts.map +1 -1
  145. package/dist/tui-ui/state.js +5 -0
  146. package/dist/tui-ui/state.js.map +1 -1
  147. package/dist/web/errors.d.ts +6 -0
  148. package/dist/web/errors.d.ts.map +1 -0
  149. package/dist/web/errors.js +13 -0
  150. package/dist/web/errors.js.map +1 -0
  151. package/dist/web/event-hub.d.ts +43 -0
  152. package/dist/web/event-hub.d.ts.map +1 -0
  153. package/dist/web/event-hub.js +323 -0
  154. package/dist/web/event-hub.js.map +1 -0
  155. package/dist/web/file-read-service.d.ts +55 -0
  156. package/dist/web/file-read-service.d.ts.map +1 -0
  157. package/dist/web/file-read-service.js +399 -0
  158. package/dist/web/file-read-service.js.map +1 -0
  159. package/dist/web/git-read-model-service.d.ts +77 -0
  160. package/dist/web/git-read-model-service.d.ts.map +1 -0
  161. package/dist/web/git-read-model-service.js +631 -0
  162. package/dist/web/git-read-model-service.js.map +1 -0
  163. package/dist/web/index.d.ts +6 -0
  164. package/dist/web/index.d.ts.map +1 -0
  165. package/dist/web/index.js +28 -0
  166. package/dist/web/index.js.map +1 -0
  167. package/dist/web/launch.d.ts +9 -0
  168. package/dist/web/launch.d.ts.map +1 -0
  169. package/dist/web/launch.js +64 -0
  170. package/dist/web/launch.js.map +1 -0
  171. package/dist/web/protocol.d.ts +408 -0
  172. package/dist/web/protocol.d.ts.map +1 -0
  173. package/dist/web/protocol.js +369 -0
  174. package/dist/web/protocol.js.map +1 -0
  175. package/dist/web/review-service.d.ts +38 -0
  176. package/dist/web/review-service.d.ts.map +1 -0
  177. package/dist/web/review-service.js +74 -0
  178. package/dist/web/review-service.js.map +1 -0
  179. package/dist/web/server.d.ts +20 -0
  180. package/dist/web/server.d.ts.map +1 -0
  181. package/dist/web/server.js +744 -0
  182. package/dist/web/server.js.map +1 -0
  183. package/dist/web/terminal-manager.d.ts +155 -0
  184. package/dist/web/terminal-manager.d.ts.map +1 -0
  185. package/dist/web/terminal-manager.js +728 -0
  186. package/dist/web/terminal-manager.js.map +1 -0
  187. package/dist/web/terminal-server.d.ts +8 -0
  188. package/dist/web/terminal-server.d.ts.map +1 -0
  189. package/dist/web/terminal-server.js +275 -0
  190. package/dist/web/terminal-server.js.map +1 -0
  191. package/dist/web/workbench-controller.d.ts +99 -0
  192. package/dist/web/workbench-controller.d.ts.map +1 -0
  193. package/dist/web/workbench-controller.js +1267 -0
  194. package/dist/web/workbench-controller.js.map +1 -0
  195. package/dist/web-client/assets/DiffViewer-DpKoD07C.js +5 -0
  196. package/dist/web-client/assets/FilesPanel-BkoLmgjR.js +2 -0
  197. package/dist/web-client/assets/GitPanel-D20StcdG.js +1 -0
  198. package/dist/web-client/assets/ReviewPanel-3MVWbMQV.js +1 -0
  199. package/dist/web-client/assets/TerminalPanel-BLQ592Fb.js +21 -0
  200. package/dist/web-client/assets/TerminalPanel-DLuoa74B.css +1 -0
  201. package/dist/web-client/assets/index-BkIDl_xk.js +16 -0
  202. package/dist/web-client/assets/index-DXMpnWE8.css +1 -0
  203. package/dist/web-client/index.html +16 -0
  204. package/docs/architecture/v0.3.0-web-api.yaml +1340 -0
  205. package/docs/architecture/v0.3.1-web-api.yaml +2290 -0
  206. package/docs/migration/v0.2.2-to-v0.3.0-settings.md +114 -0
  207. package/docs/migration/v0.2.2-to-v0.3.0.md +55 -0
  208. package/docs/migration/v0.3.0-to-v0.3.1.md +88 -0
  209. package/docs/orion.example.json +9 -2
  210. package/docs/plan/v0.3.0-node-runtime-compatibility-plan.md +57 -0
  211. package/docs/plan/v0.3.0-settings-integration-plan.md +740 -0
  212. package/docs/plan/v0.3.0-web-workbench-plan.md +376 -0
  213. package/docs/plan/v0.3.1-web-workbench-professional-shell-plan.md +848 -0
  214. package/docs/readme.md +22 -1
  215. package/docs/test/v0.3.1-web-workbench-e2e-plan.md +140 -0
  216. package/npm-shrinkwrap.json +1229 -45
  217. package/package.json +47 -11
@@ -0,0 +1,376 @@
1
+ # Orion Code v0.3.0 Web Workbench Development Plan
2
+
3
+ > Status: implementation complete; local release candidate gates passed
4
+ >
5
+ > Target version: `v0.3.0`
6
+ >
7
+ > Implementation branch: `v0.3.0`
8
+ >
9
+ > Baseline: `v0.2.2@40d02f6`
10
+ >
11
+ > API contract: [v0.3.0 Web API](../architecture/v0.3.0-web-api.yaml)
12
+ >
13
+ > Settings lifecycle and release gates:
14
+ > [v0.3.0 Settings integration plan](v0.3.0-settings-integration-plan.md)
15
+ >
16
+ > DSH source reference: `deepseek-ai/deepseek-harness@b150a551b8d465e31e418e1b2eaf5e79bbb7d28e`
17
+
18
+ ## 1. Product outcome
19
+
20
+ v0.3.0 turns Orion Code into a local-first coding-agent product with a complete browser surface.
21
+ The browser can select a workspace, create and resume sessions, run AI coding tasks, inspect
22
+ streaming messages and tool activity, answer approvals, control Goal and Plan mode, select models,
23
+ inspect Skills/MCP and runtime diagnostics, and recover after a refresh or disconnect.
24
+
25
+ The Web surface is an adapter over the same product runtime used by the terminal UIs. It does not
26
+ own a second agent loop, permission implementation, session database, or completion model.
27
+
28
+ ### Completion requirements
29
+
30
+ | Requirement | Authoritative proof |
31
+ | ----------------------------------------------------------- | ----------------------------------------------------------- |
32
+ | `orion web` starts the workbench | Packaged CLI smoke test and HTTP health response |
33
+ | Workspace and session management | Web API contract tests plus browser workflow test |
34
+ | Streaming conversation, reasoning, tools, edits and results | Ordered event-stream integration test |
35
+ | Approval, Goal, Plan, Skills, MCP, model and diagnostics | Endpoint/command tests and UI workflow coverage |
36
+ | Refresh/disconnect recovery | Cursor replay test with no duplicate command execution |
37
+ | Shared Web/TUI/CLI runtime and persistence | Runtime parity test over one fixed scenario |
38
+ | Loopback and browser security | bind, Origin, nonce, CSP, redaction and path-boundary tests |
39
+ | npm distribution includes the Web UI | tarball inspection and installed-artifact smoke test |
40
+
41
+ ## 2. Reference decisions
42
+
43
+ The official DeepSeek Harness source is cloned separately under
44
+ `~/ai-project/deepseek-harness` and pinned to the commit above. Orion adopts the useful product
45
+ separation demonstrated there: a browser-only HTTP carrier, a runtime bridge owned by another
46
+ layer, workspace selection before composing tasks, and settings that affect later requests without
47
+ restarting the server.
48
+
49
+ The pinned DSH browser implementation is **not an SSE design**. Its unary calls travel as HTTP
50
+ `POST` requests, while `packages/client/connection/src/client/web-api-client.ts` opens two
51
+ server-to-browser, downlink-only WebSockets at `/api/events.mux` and `/api/events.host`. The generic
52
+ API-proxy fetch carrier also supports SSE, but the browser subclass overrides those event streams
53
+ with WebSockets. Orion deliberately chooses a smaller transport for v0.3.0: JSON `POST`/mutation
54
+ requests plus one replayable SSE downlink. This is a product decision, not a claim that DSH uses the
55
+ same carrier.
56
+
57
+ Orion does not copy DSH source or branding and does not adopt its public plugin composition model.
58
+ The existing Orion boundaries remain authoritative: Model, Skills, MCP, Tools, TaskContext,
59
+ Goal/Evidence and the single `ThreadRuntimeV1` execution path.
60
+
61
+ ## 3. Architecture
62
+
63
+ ```text
64
+ Browser (React/Vite)
65
+ -> same-origin JSON command/query API
66
+ -> SSE event stream with durable cursor
67
+ Loopback Web Host (node:http)
68
+ -> WebWorkbenchController
69
+ -> AgentRuntimeController / OrionSessionRunnerV1
70
+ -> OrionRuntimeV1 / ThreadRuntimeV1
71
+ -> existing Session, Goal, config, Skill and MCP stores
72
+ ```
73
+
74
+ ### Host and transport
75
+
76
+ - `orion web [--port <0-65535>] [--no-open] [--cwd <directory>]` binds only `127.0.0.1`;
77
+ port `0` selects an OS port.
78
+ - Static assets and `/api/v1/*` use one origin. There is no CORS response and no network bind
79
+ option in v0.3.0.
80
+ - Queries and commands use JSON HTTP. Live renderer-neutral events use SSE so reconnects can carry
81
+ an acknowledged cursor without adding a second socket command protocol.
82
+ - Every mutation, including workspace/session transitions, settings changes and runtime commands,
83
+ has a client-generated `requestId`. A bounded result cache keyed by both `requestId` and request
84
+ digest makes exact retries idempotent for the lifetime of the server process; reuse with a
85
+ different body returns `409 Conflict`. Accepted IDs are never evicted: after 4,096 distinct
86
+ mutations the Host fails new IDs closed with `503 mutation_capacity_exhausted` until restart,
87
+ instead of risking duplicate side effects.
88
+ - Every runtime command also carries `expectedSessionId`. The Host compares it with the active
89
+ Session in the same synchronous admission step as dispatch; a concurrent Session transition or
90
+ mismatch returns `409 active_session_changed`/`runtime_busy` without executing or replaying the
91
+ command.
92
+ - Settings are a compare-and-swap resource. Reads return `revision`; writes carry both `requestId`
93
+ and `expectedRevision`, and a stale revision returns `409 Conflict` without applying any field.
94
+ - Durable events have increasing cursors and are replayed after reconnect. Ephemeral deltas may be
95
+ coalesced; the next durable transcript state repairs any missed delta.
96
+ - Every event envelope includes `sessionId` and `threadId`. Runtime events require both keys but
97
+ allow either value to be `null` before a session/Thread exists; committed Thread events require
98
+ both identities to be non-null.
99
+ - Collection reads use bounded, revision-bound keyset pagination. The opaque cursor binds route
100
+ scope, the complete ordered collection digest and the last stable item key. If the collection
101
+ changes, the Host returns `409 collection_cursor_stale`; the browser reloads page one instead of
102
+ risking duplicate or skipped items. These cursors are distinct from the monotonically increasing
103
+ numeric SSE cursor.
104
+
105
+ ### HTTP read and mutation surface
106
+
107
+ | Surface | Contract | Notes |
108
+ | ------------ | ---------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
109
+ | Workspaces | `GET /workspaces`, `POST /workspaces/activate` | Cursor-paged read; activation has `requestId` |
110
+ | Sessions | `GET/POST /sessions`, `POST /sessions/{id}/activate`, `PATCH /sessions/{id}` | Every write has `requestId` |
111
+ | Recovery | `GET /sessions/{id}/snapshot` | Cursor-paged TranscriptPage plus Thread and SSE recovery state |
112
+ | Skills | `GET /skills` | Cursor-paged safe `SkillDescriptorV1` metadata only |
113
+ | MCP | `GET /mcp` | Cursor-paged runtime summaries; no command, URL, headers or credentials |
114
+ | Tool details | `GET /tool-details`, `GET /tool-details/{callId}` | Active-workspace summaries and byte-paged redacted output |
115
+ | Settings | `GET/PATCH /settings` | Revisioned snapshot and `expectedRevision` CAS |
116
+ | Runtime | `POST /commands`, `GET /events` | Idempotent mutations plus one replayable SSE stream |
117
+
118
+ The session snapshot follows `WebSessionSnapshotV1` exactly: nullable `threadId`, independent
119
+ `threadCursor` and `eventCursor`, optional `projectionDigest`/`activeTurnId`, `threadStatus`, a
120
+ cursor-paged `TranscriptPage`, the runtime view, pending approvals, nullable TurnCommit Goal and
121
+ three-field Plan projections, and `recoveryDiagnostics`. A legacy snapshot has `threadId: null` and
122
+ `threadStatus: legacy`; the Web client must not synthesize a Thread identity. A v2 transcript cursor
123
+ binds the Thread identity and immutable transcript-manifest revision. A newer Thread makes an older
124
+ cursor fail with `409 transcript_cursor_stale`, requiring a fresh tail snapshot.
125
+
126
+ Tool details are workspace/project-scoped because the current artifact metadata records artifact
127
+ identity, tool name and byte size but no `sessionId`. The API resolves only against the active
128
+ workspace and never exposes the artifact path. Byte ranges address a pre-sanitized derivative,
129
+ never the raw artifact, so an arbitrary offset cannot skip a sensitive-field label. The API still
130
+ cannot claim or prove that an artifact belongs to a particular session. Session-scoped routes
131
+ require a future provenance-bearing artifact format and are not part of the v0.3.0 contract.
132
+
133
+ ### 2026-08-29 — long-session paging closure
134
+
135
+ - Added a persisted, digest-bound Thread head and immutable transcript page manifest. A healthy
136
+ fresh-process v2 snapshot reads the requested page directly and does not reopen the full
137
+ projection or replay the JSONL log; missing, stale or corrupt derived state falls back to one
138
+ authoritative rebuild.
139
+ - The browser now loads one bounded page for Workspaces, Sessions, Skills, MCP and tool-detail
140
+ summaries. Additional pages require an explicit user action; it no longer drains every page into
141
+ memory during bootstrap.
142
+ - Collection continuations and transcript continuations now have separate stale-cursor contracts,
143
+ both fail closed with 409, and both have Host/client/reducer regression coverage.
144
+ - The verification figures below predate this storage evolution. A fresh exact-tarball browser and
145
+ Node 22/24/26 release matrix must be generated before this newer candidate can be called complete.
146
+
147
+ ### Runtime ownership
148
+
149
+ - The Web host constructs the same `OrionCodeUiRuntime`, `AgentRuntimeController`,
150
+ `OrionSessionRunnerV1` and `OrionRuntimeV1` composition used by interactive CLI surfaces.
151
+ - The host projects typed `AgentRuntimeEvent` values into a versioned Web envelope. Presentation
152
+ code never parses terminal text to recover tool, approval, Goal or diagnostic state.
153
+ - The latest valid `TurnCommitV1` is the sole authority for committed Goal state and its digest.
154
+ A legacy Goal sidecar may be read once only as a migration seed when no committed Goal state
155
+ exists; after the seed is committed, it is never merged with, preferred over, or presented as a
156
+ second authority. v0.3.0 requires no destructive migration of the old file.
157
+ - Plan projection comes only from the `PlanReceiptV1` bound into `TurnCommitV1`. The Web read model
158
+ exposes exactly `body`, `returnMode` (`build` or `auto`) and `digest`; it does not invent review,
159
+ approval, status or step state. A valid Plan turn commits without implementing, then Orion
160
+ restores `returnMode` and automatically starts a separate execution request after the current
161
+ turn finishes. No second user message or Web-only approval phase exists.
162
+ - Thread event logs, TurnCommit journals, compact checkpoints and permission grants remain shared
163
+ durable sources. Browser projections never become an independent write authority.
164
+ - Only one active product runtime owns a selected session. Switching workspace/session drains the
165
+ old owner before starting or replaying the next one.
166
+
167
+ ### Approval lifetime
168
+
169
+ - The runtime, not a browser connection, owns each pending approval and its stable request ID.
170
+ Approval scopes are exactly `once`, `project` and `global`; there is no Web-only `session` scope.
171
+ - Network loss, SSE reconnect, refresh and closing a tab leave the approval pending. A session
172
+ snapshot and subsequent events re-project it after reconnect; a disconnected browser never
173
+ implies consent or denial.
174
+ - Explicit user denial resolves the request normally. Runtime abort, process shutdown, forced
175
+ session/workspace teardown and an unrecoverable approval-owner failure resolve every affected
176
+ request as denied and fail the waiting tool call closed.
177
+
178
+ ### Security boundary
179
+
180
+ - A random per-process nonce is returned by the same-origin `/api/v1/bootstrap` handshake. Mutating
181
+ requests require it in `X-Orion-Web-Nonce`; the value is never written to disk or logs.
182
+ - Mutations require an exact loopback Origin. Requests with missing/foreign Origin, invalid content
183
+ type or oversized bodies fail closed.
184
+ - Responses set CSP, `frame-ancestors 'none'`, `X-Content-Type-Options: nosniff`, no-store API
185
+ caching and conservative referrer policy.
186
+ - Browser payloads expose configured provider/model metadata but never API keys, authorization
187
+ headers, environment values or raw secret-bearing config.
188
+ - Workspace paths are canonical real directories. Session selection is permitted only when its
189
+ canonical project matches the active workspace; file activity remains constrained by the
190
+ existing ToolGateway and workspace-containment policies.
191
+
192
+ ## 4. Workbench experience
193
+
194
+ The desktop layout uses a workspace/session rail, a central transcript and composer, and a details
195
+ inspector. On narrow screens the rails become accessible dialogs/drawers without removing features.
196
+
197
+ - **Workspace/session rail:** current canonical workspace, recent sessions, search, new session,
198
+ resume and rename; active/running/Goal badges.
199
+ - **Transcript:** Markdown messages, streamed reasoning, structured tool cards, commands, MCP,
200
+ subagents, research, edits, errors and compact lifecycle. Long output is collapsed with a safe
201
+ plain-text expansion.
202
+ - **Composer:** BUILD/PLAN/AUTO selector backed by `set_agent_mode` with explicit `agentMode`
203
+ (`interactive`, `plan` or `auto`), multiline prompt, submit, steer/follow-up while running,
204
+ interrupt, queue display and keyboard shortcuts.
205
+ - **Approval sheet:** tool identity, reason, sanitized arguments and allow/deny for once/project/
206
+ global. Refresh, disconnect or closing the tab preserves pending requests; runtime abort or
207
+ shutdown denies them fail-closed.
208
+ - **Inspector:** committed Goal state and evidence; the Plan receipt's body, return mode and digest;
209
+ context pressure, token/cost statistics, current model/effort, Skills/MCP catalog state,
210
+ verification and Harness diagnostics. It has no synthetic Plan review, status or steps.
211
+ - **Settings:** model and effort selection plus tool-confirmation policy. Secret entry is excluded
212
+ from v0.3.0; credentials stay in Orion configuration/environment and only configured status is
213
+ shown.
214
+ - **Recovery states:** reconnecting, replaying, unavailable model, damaged session, command
215
+ rejected/busy, approval expired and server shutdown are explicit states with safe recovery
216
+ actions.
217
+
218
+ Accessibility is part of the release gate: semantic landmarks, labelled controls, visible focus,
219
+ keyboard-complete composer/dialogs, reduced motion, status live regions and WCAG AA contrast.
220
+
221
+ ## 5. Delivery phases
222
+
223
+ 1. **Reference and contract:** pin/audit DSH source, commit this plan and the OpenAPI contract, and
224
+ add shared Web wire types with validators.
225
+ 2. **Runtime bridge:** extract the product bootstrap into a reusable composition root; implement
226
+ workspace/session lifecycle, Goal/Plan TurnCommit projections, idempotent mutations, settings
227
+ CAS, approval recovery, paginated read models and event replay.
228
+ 3. **Loopback host:** implement routing, static serving, SSE, nonce/Origin/body limits, health and
229
+ graceful shutdown.
230
+ 4. **Workbench client:** build the responsive React application and all required runtime panels,
231
+ using only contract-derived API types.
232
+ 5. **Distribution:** add `orion web`, Web build/copy scripts, npm file manifest, version reporting,
233
+ README/CHANGELOG/migration notes and release receipt coverage.
234
+ 6. **Verification:** run protocol, security, runtime parity, browser workflow, build, full Jest,
235
+ lint, coverage, tarball and clean-install smoke gates. Record failures and repairs in this file.
236
+
237
+ ## 6. Release gates
238
+
239
+ v0.3.0 is `GO` only when every completion requirement has direct evidence; no Web path can bypass
240
+ ToolGateway approval/sandbox policy; every mutation proves `requestId` replay behavior; settings
241
+ prove stale-revision rejection; refresh/reconnect neither duplicates a mutation nor resolves a
242
+ pending approval; abort/shutdown deny pending approvals; Goal and Plan projections match the latest
243
+ valid TurnCommit; API secrets are absent from captured browser traffic; and one packed tarball
244
+ passes `orion web` on every supported Node major version. A successful local frontend build alone
245
+ is not a release result.
246
+
247
+ ## 7. Delivery record
248
+
249
+ This section is append-only during implementation. Record the final DSH paths inspected, contract
250
+ changes, implementation milestones, failed gates and repairs, exact verification commands, tarball
251
+ identity and the final release decision.
252
+
253
+ ### 2026-08-27 — reference audit and contract closure
254
+
255
+ - Confirmed the pinned DSH browser carrier in
256
+ `packages/client/connection/src/client/web-api-client.ts`,
257
+ `packages/client/connection/src/websocket-downlink.ts` and
258
+ `packages/client/connection/src/api-path.ts`: HTTP POST upstream plus two downlink-only
259
+ WebSockets. The generic API-proxy SSE carrier is not the browser-selected implementation.
260
+ - Cross-checked Orion ownership and safe read fields against `src/runtime/turn-commit.ts`,
261
+ `src/runtime/thread-ui-adapter.ts`, `src/runtime/tool-detail-repository.ts`,
262
+ `src/runtime/skills/types.ts` and `src/runtime/mcp/types.ts`.
263
+ - Closed the API contract around paginated read models, request idempotency, settings CAS,
264
+ TurnCommit-owned Goal/Plan projections, reconnect-safe approvals and a discriminated SSE event
265
+ union. YAML parsing, all internal `$ref` targets, unique operation IDs, mutation `requestId`
266
+ requirements, exact Plan fields and event branch scope/UUID fields were checked locally; both
267
+ documents also pass whitespace-error checks.
268
+
269
+ ### 2026-08-27 — implemented wire-contract reconciliation
270
+
271
+ - Reconciled the docs with `src/web/protocol.ts`, `src/web/server.ts`,
272
+ `src/web/workbench-controller.ts` and `src/web/event-hub.ts`: the recovery snapshot now names the
273
+ exact required and optional fields, runtime-event identities are nullable, and explicit agent-mode
274
+ selection uses `set_agent_mode` plus `agentMode`.
275
+ - Moved tool-detail reads to active-workspace `/tool-details` routes. The existing project artifact
276
+ metadata cannot prove session ownership, so neither the plan nor API promises session
277
+ attribution.
278
+ - Removed the invented Goal state schema; only the TurnCommit authority/digest wrapper is typed and
279
+ its `state` remains the source-defined opaque JSON value. `ToolDetailPage.nextOffsetBytes` now
280
+ permits omission or null at end of output.
281
+
282
+ ### 2026-08-27 — implementation and release-candidate closure
283
+
284
+ - Extracted `createProductUiRuntime` into the shared product bootstrap and connected the Web host
285
+ to the same `AgentRuntimeController`, `OrionSessionRunnerV1`, `OrionRuntimeV1`, Session/Thread,
286
+ Goal, ToolDetail, Skill and MCP owners used by the terminal products. Root and child runtimes now
287
+ rebind from the selected model profile rather than retaining a stale bootstrap model.
288
+ - Added the loopback-only `node:http` host, validated Web wire protocol, process-lifetime mutation
289
+ idempotency, settings CAS, bounded query/output paging, redacted projections, recovery snapshots,
290
+ replayable SSE with reset/slow-client behavior, exact Origin/Host/nonce checks and graceful
291
+ fail-closed shutdown.
292
+ - Added the responsive React/Vite Workbench with workspace/session navigation, transcript and
293
+ composer, BUILD/PLAN/AUTO, follow-up/interrupt, approval dialogs, Goal/Plan projections, paged
294
+ tool output, settings, Skill/MCP catalog and diagnostics. The client obtains a snapshot before
295
+ opening SSE and reconnects from `eventCursor`, preventing snapshot/event startup races.
296
+ - Added `orion web`, npm Web asset packaging, v0.2.2 migration guidance, English/Chinese usage,
297
+ changelog entries, CI browser coverage and packaged-runtime Web probes. React stays a build-only
298
+ dependency because the published browser bundle is self-contained.
299
+ - Applied the accessibility audit to the actual rendered application. Semantic landmarks,
300
+ dialog/drawer labels, focus and Escape behavior, live status, `aria-expanded`/`aria-controls`,
301
+ reduced motion and contrast tokens were repaired; the real Chrome + axe WCAG 2.2 AA journey
302
+ reports zero blocking and zero non-blocking violations.
303
+
304
+ ### Failed gates and repairs
305
+
306
+ - The first full Jest run used the then-unsupported Node 26 against native modules built for
307
+ Node 24. The rerun proved this was an ABI/environment mismatch. The current compatibility
308
+ contract supersedes that historical matrix and runs release gates on Node 22.12+/24/26 with an
309
+ isolated install for each ABI.
310
+ - A later long-lived Node 24 Jest process terminated with a process-level `SIGSEGV` after its early
311
+ suites passed, while direct native probes remained healthy. To avoid rewriting the shared
312
+ dependency tree used by long-running Orion processes, the authoritative full regression ran in
313
+ an isolated Node 22 clean install.
314
+ - Two non-executable benchmark TypeScript modules retained shebangs that `ts-jest` preserved when
315
+ importing them. Removing those ineffective shebangs restored deterministic importability.
316
+ - Existing architecture/package tests still expected CLI-private bootstrap and a server-only build.
317
+ They were updated to assert the shared bootstrap and the clean server + client build pipeline.
318
+ - Dependency governance initially treated every React occurrence as the retired Ink renderer.
319
+ The gate now continues to forbid Ink and runtime React while requiring React 18 and its types only
320
+ as Web build dependencies.
321
+ - Browser review found a snapshot/SSE startup race, insufficient contrast and incomplete mobile
322
+ drawer state semantics. Baseline-before-stream ordering, dedicated contrast tokens and explicit
323
+ drawer ARIA state repaired those failures before the browser gate was accepted.
324
+
325
+ ### Verification result
326
+
327
+ - `npm run lint`, `npm run build`, `git diff --check`, `npm audit --audit-level=high` and
328
+ `npm audit --omit=dev --audit-level=high`: pass; production build emits 37 client modules, about
329
+ 230.33 kB JavaScript and 41.03 kB CSS before gzip.
330
+ - Isolated Node 22 `npm ci` full Jest: 281 of 282 suites passed, 3,498 tests passed and 5 skipped;
331
+ its only failure was the copied test directory intentionally lacking `.git`, which prevented the
332
+ immutable Phase 0 `git archive` fixture from opening. Re-running that exact remaining suite with
333
+ the source Git directory bound passed all 12 tests. Together the clean-install regression covers
334
+ all 282 suites and 3,504 test cases with no product-code failure.
335
+ - `npm run test:web-browser`: loopback health, real session mutation, responsive drawer and Chrome
336
+ axe journey pass with zero WCAG A/AA/2.1 AA/2.2 AA violations.
337
+ - `npm run release:check -- --allow-dirty --skip-tests`: version/CHANGELOG, ESLint, TypeScript,
338
+ exact npm pack, clean install, CLI identity/help, native SQLite and packaged Web health/static
339
+ probes pass. The dirty warning is expected for this uncommitted candidate and includes one
340
+ pre-existing user-owned plan edit that this implementation did not modify.
341
+ - The exact package name/version is `@orion-agents/orion-code@0.3.0`. Tarball SHA-256 and the
342
+ Node-major matrix receipts are generated outside the package payload to avoid a self-referential
343
+ embedded hash; the final release-gate output is authoritative.
344
+
345
+ ### Release decision
346
+
347
+ The local v0.3.0 source candidate has passed the final PATH-bound Jest and exact-tarball
348
+ Node 22/24/26 matrix. Historical 20/22/24 receipts do not satisfy the current contract. The local
349
+ artifact still records a dirty source tree, so a source-clean commit must generate a new tarball and
350
+ obtain digest-bound remote receipts before publication. This plan does not itself claim a commit,
351
+ push, tag, GitHub Release or npm publication.
352
+
353
+ ### 2026-08-29 — composer dock, recovery and paging quality closure
354
+
355
+ - The center column is now an explicit header/transcript/composer grid. Transcript history scrolls
356
+ independently while pending approvals, the follow-up queue and the composer remain in a bounded
357
+ bottom dock; the mobile Steer action remains reachable. Drafts are keyed by Session, and streaming
358
+ growth is observed without forcing users who scrolled upward back to the tail.
359
+ - Snapshot recovery now rejects inactive or mismatched Session state, treats `replay_reset` as a
360
+ terminal barrier, and binds every Session command to the expected active Session. Collection
361
+ continuations and transcript continuations use separate revision-bound cursors; the browser loads
362
+ only the first page until the user explicitly asks for more.
363
+ - Large tool output is served only from a pre-sanitized browser derivative. The derivative byte
364
+ offset is the paging authority, so arbitrary offsets cannot bypass label-based redaction in the
365
+ raw artifact.
366
+ - The exact local candidate tgz, bound to the receipt stored outside the package payload, passed the
367
+ complete system Chrome 152 journey, 22/22 scenarios, on Node 22.22.3. The run records
368
+ `layout.composer_docked=true`, zero console errors/warnings, zero page errors, zero HTTP 5xx, zero
369
+ secret findings and zero dropped events.
370
+ - The same source passed 289/289 Jest suites and 3,620 tests, with 5 existing platform-conditioned
371
+ skips. The generated client contains 44 modules (277.19 kB JavaScript and 54.45 kB CSS before
372
+ gzip).
373
+
374
+ This remains a dirty local development candidate. A source-clean commit must produce a new SHA and
375
+ obtain the required Node 22/24/26 receipts before push, release tagging or npm publication can be
376
+ described as complete.