@orion-agents/orion-code 0.3.4 → 0.3.7
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.
- package/CHANGELOG.md +124 -0
- package/README.md +61 -5
- package/README.zh-CN.md +7 -3
- package/dist/commands/context-tool-command-handlers.js +1 -5
- package/dist/commands/registry.js +1 -4
- package/dist/harness/intent.js +69 -16
- package/dist/harness/turn-summary.js +3 -1
- package/dist/memory/embeddings.js +2 -3
- package/dist/memory/prompts.js +1 -1
- package/dist/memory/relevant-finder.js +125 -15
- package/dist/memory/vector-store.js +13 -8
- package/dist/migration/migrate.js +8 -12
- package/dist/runtime/composer/history.js +1 -3
- package/dist/runtime/composer/layout.js +7 -4
- package/dist/runtime/legacy-thread-materializer.d.ts +3 -1
- package/dist/runtime/legacy-thread-materializer.js +15 -3
- package/dist/runtime/product-bootstrap.d.ts +12 -0
- package/dist/runtime/product-bootstrap.js +37 -22
- package/dist/runtime/rich-text/ansi-parser.js +12 -2
- package/dist/runtime/rich-text/layout.js +15 -19
- package/dist/runtime/subagents/budget.js +4 -1
- package/dist/runtime/subagents/policy.js +11 -4
- package/dist/runtime/subagents/provider-gate.js +6 -4
- package/dist/runtime/subagents/research-quality.js +3 -1
- package/dist/runtime/subagents/research-renderer.js +9 -2
- package/dist/runtime/subagents/result-parser.js +18 -7
- package/dist/runtime/thread-event-store.d.ts +5 -3
- package/dist/runtime/thread-event-store.js +29 -8
- package/dist/runtime/thread-projection.d.ts +17 -0
- package/dist/runtime/thread-projection.js +42 -1
- package/dist/runtime/tool-output-presentation.js +7 -7
- package/dist/runtime/turn-controller.js +1 -2
- package/dist/services/auth/auth.js +1 -4
- package/dist/services/auth/aws.js +24 -14
- package/dist/services/auto-fix/autoFixRunner.js +1 -1
- package/dist/services/auto-fix/index.d.ts +1 -1
- package/dist/services/diagnostic-tracking/diagnosticTracking.js +4 -2
- package/dist/services/diagnostic-tracking/index.d.ts +1 -1
- package/dist/services/effort.js +1 -9
- package/dist/services/file-glob.js +3 -4
- package/dist/services/mcp/transports.js +4 -4
- package/dist/services/model-catalog.js +179 -30
- package/dist/services/model-context.js +1 -1
- package/dist/services/provider-resilience/stream-recovery.js +1 -3
- package/dist/services/session-storage.d.ts +28 -3
- package/dist/services/session-storage.js +70 -6
- package/dist/services/smart-routing.js +19 -11
- package/dist/services/verification-profile.js +17 -22
- package/dist/services/web-search-provider.js +21 -9
- package/dist/services/workspace-diff.js +10 -4
- package/dist/skills/builtin/code-review/SKILL.md +1 -1
- package/dist/skills/builtin/security-check/SKILL.md +1 -1
- package/dist/skills/builtin/test-gen/SKILL.md +1 -1
- package/dist/terminal-ui/editor.js +6 -2
- package/dist/terminal-ui/output-queue.js +9 -3
- package/dist/tools/lsp.js +12 -6
- package/dist/tui-core/frame.js +9 -7
- package/dist/tui-ui/transcript-cache.js +6 -6
- package/dist/tui-ui/transcript-inspector-surface.js +4 -1
- package/dist/tui-ui/transcript-inspector.js +3 -8
- package/dist/ui/box.js +14 -7
- package/dist/ui/markdown.js +4 -2
- package/dist/ui/shared/input-frame.js +12 -8
- package/dist/ui/stream-markdown.js +1 -1
- package/dist/ui/tool-preview.js +11 -3
- package/dist/ui/user-input.js +16 -10
- package/dist/web/protocol.d.ts +2 -0
- package/dist/web/protocol.js +1 -0
- package/dist/web/server.js +69 -0
- package/dist/web/session-runtime-registry.d.ts +14 -0
- package/dist/web/session-runtime-registry.js +23 -0
- package/dist/web/workbench-controller.d.ts +55 -0
- package/dist/web/workbench-controller.js +224 -14
- package/dist/web-client/assets/{DiffViewer-D6mG729y.js → DiffViewer-DqbZ02RN.js} +1 -1
- package/dist/web-client/assets/{FilesPanel-CCDoAZ1J.js → FilesPanel-Bu1Ab2kJ.js} +1 -1
- package/dist/web-client/assets/{GitPanel-DtNgiH7A.js → GitPanel-BixIWb4k.js} +1 -1
- package/dist/web-client/assets/ReviewPanel-DsqJpku_.js +1 -0
- package/dist/web-client/assets/{TerminalPanel-CNxMaBLp.js → TerminalPanel-DdjQP2mp.js} +1 -1
- package/dist/web-client/assets/index-30GT9Vnx.js +17 -0
- package/dist/web-client/assets/index-DQfpqPTD.css +1 -0
- package/dist/web-client/index.html +2 -2
- package/npm-shrinkwrap.json +356 -120
- package/package.json +3 -1
- package/dist/web-client/assets/ReviewPanel-CKEBSt6P.js +0 -1
- package/dist/web-client/assets/index-BBvNg3By.css +0 -1
- package/dist/web-client/assets/index-C6TDJwMC.js +0 -17
package/CHANGELOG.md
CHANGED
|
@@ -22,6 +22,130 @@ which is **not** a pass.
|
|
|
22
22
|
|
|
23
23
|
## [Unreleased]
|
|
24
24
|
|
|
25
|
+
## [0.3.7] — CANDIDATE
|
|
26
|
+
|
|
27
|
+
> **Status: candidate.** This work is isolated on the codex/v0.3.7 worktree (left project
|
|
28
|
+
> rail interaction quality). It is not merged, tagged or published to npm.
|
|
29
|
+
|
|
30
|
+
### Added
|
|
31
|
+
|
|
32
|
+
- Session **tags**: up to 8 user-assigned tags per Session (each ≤ 32 chars), persisted on
|
|
33
|
+
the Session record (`SessionMeta.tags`), projected into `WebSessionSummaryV1.tags`,
|
|
34
|
+
managed from a new "管理标签…" dialog (chip add via Enter/comma, per-chip remove) and
|
|
35
|
+
rendered as small badges on rail rows. Host endpoint `POST /sessions/:id/tags`.
|
|
36
|
+
- Session **archive / restore**: soft delete via `SessionMeta.archivedAt` that keeps every
|
|
37
|
+
file, hides the Session from default listings and counts, and surfaces it under a new
|
|
38
|
+
"已归档" rail section with a 还原 action (`POST /sessions/:id/archive|restore`;
|
|
39
|
+
`GET /workspaces/:id/sessions/archived`).
|
|
40
|
+
- Session **delete** from the web workbench: destructive confirmation dialog (explicit
|
|
41
|
+
"永久删除" guard, 不可恢复 copy) wired to the existing storage `deleteSession` through a
|
|
42
|
+
new `DELETE /sessions/:id` endpoint; refuse-while-busy checks in the controller.
|
|
43
|
+
- The rail rename affordance becomes a general **overflow menu** (`SessionRowMenu`,
|
|
44
|
+
keyboard navigable ↑↓/Home/End/Esc with focus restore) hosting 重命名… / 管理标签… /
|
|
45
|
+
归档 / 删除… so future per-Session actions have a stable home.
|
|
46
|
+
|
|
47
|
+
### Changed
|
|
48
|
+
|
|
49
|
+
- Active-workspace session listings (`listProjectSessions`, `listSessions`,
|
|
50
|
+
`countSessionsByProject`) exclude archived Sessions by default.
|
|
51
|
+
- Rail footer status copy is shortened to 已连接 / 离线 / … with full sentences moved to a
|
|
52
|
+
tooltip (`connectionTitle`); the collapsed rail dot keeps an accessible short label.
|
|
53
|
+
- Project tag chips, archived-section rows and the two new dialogs ship with their own
|
|
54
|
+
styles; stale `.session-rename`/`.session-row` rules were removed.
|
|
55
|
+
|
|
56
|
+
### Fixed
|
|
57
|
+
|
|
58
|
+
- Rename failures are no longer silent: `RenameDialog` surfaces the server error inline
|
|
59
|
+
(`field-error`) instead of closing without feedback.
|
|
60
|
+
- Session-row menu hint ids are instance-unique (`useId`) so `aria-describedby` can never
|
|
61
|
+
point at another row's hint.
|
|
62
|
+
- The archived rail listing is bound to its owning Workspace: switching projects drops stale
|
|
63
|
+
foreign archive rows immediately and never flashes another project's archive while loading;
|
|
64
|
+
`session_deleted` also clears the stale runtime projection.
|
|
65
|
+
|
|
66
|
+
### Tests
|
|
67
|
+
|
|
68
|
+
- New contract suites: `web-reducer-session-lifecycle` (14, incl. owner-binding + runtime
|
|
69
|
+
cleanup regression), `web-ui-SessionDialogs` (7), `web-ui-SessionRowMenu` (3),
|
|
70
|
+
`web-ui-WorkspaceDialog` (6), `session-storage-tags-archive` (5, incl. delete),
|
|
71
|
+
plus controller-level guards (tags validation / archive-restore / delete-while-busy /
|
|
72
|
+
foreign-workspace rejection / 404) in `web-workbench-controller.test.ts`; `web-ui-*` now
|
|
73
|
+
112 cases green. E2E: `web-v037-session-lifecycle.spec.ts` (archive/restore, delete-confirm,
|
|
74
|
+
tags round-trip) runs in CI.
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
## [0.3.6] — CANDIDATE
|
|
78
|
+
|
|
79
|
+
> **Status: candidate.** This work is isolated on the codex/v0.3.6 worktree (pure web
|
|
80
|
+
> workbench interaction quality). It is not merged, tagged or published to npm.
|
|
81
|
+
|
|
82
|
+
### Added
|
|
83
|
+
|
|
84
|
+
- Component rendering contract layer for the web workbench: six `.test.tsx` suites
|
|
85
|
+
(89 cases) assert on `react-dom/server.renderToStaticMarkup` output without jsdom —
|
|
86
|
+
Markdown / StateDot / ShortcutHelp / DiffViewer / ApprovalCard / PanelResize.
|
|
87
|
+
- `StateDot` status indicator that never relies on colour alone (WCAG 1.4.1): every dot
|
|
88
|
+
carries a shape channel via `data-tone` (square / circle / pulsing ring / hollow ring /
|
|
89
|
+
triangle) plus a visually-hidden text label for assistive tech; applied to reasoning,
|
|
90
|
+
research sources, review evidence and the work-panel rail.
|
|
91
|
+
- Single-source keyboard binding table (`shortcuts.ts`) plus a `⌘/` shortcut help dialog
|
|
92
|
+
rendered from it, so the panel cannot drift from the live bindings; `matchesShortcut`
|
|
93
|
+
now resolves `Esc` → `Escape` so the help vocabulary matches real key events.
|
|
94
|
+
- Header theme-cycle button (system → light → dark, persisted through the settings
|
|
95
|
+
document); the `SettingsDialog` entry stays intact.
|
|
96
|
+
- Stacked notification toasts (P1-C): multiple notices queue without overwriting, each
|
|
97
|
+
non-recoverable non-error notice auto-dismisses after 5s, error / recovery notices stay
|
|
98
|
+
until acted on, and `aria-live` is graded (alert for errors, status otherwise).
|
|
99
|
+
|
|
100
|
+
### Changed
|
|
101
|
+
|
|
102
|
+
- `PanelResizeHandle` is keyboard reachable with full separator semantics: `role=separator`
|
|
103
|
+
with live `aria-valuenow`/`aria-valuetext`, ←/→ steps of 2% (Shift 10%), Home/End jump,
|
|
104
|
+
Enter/Space reset to default; stepping logic is extracted as pure functions.
|
|
105
|
+
- Notification region becomes a stacked container (`.workbench-notice-stack`); cards slide
|
|
106
|
+
in on `opacity`/`transform` only and the whole stack is inert while drawers are open.
|
|
107
|
+
- Icon set gains `sun` / `moon` / `monitor` / `keyboard` glyphs.
|
|
108
|
+
|
|
109
|
+
### Fixed
|
|
110
|
+
|
|
111
|
+
- Markdown heading off-by-one: `##` renders as `<h2>` (was `<h3>`), a lone `#` no longer
|
|
112
|
+
collapses to `<h6>`; >6 hashes stay a plain paragraph per GFM.
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
## [0.3.5] — CANDIDATE
|
|
116
|
+
|
|
117
|
+
> **Status: candidate.** This work is isolated on the codex/v0.3.5 worktree. It is not
|
|
118
|
+
> merged, tagged or published to npm, and exact-artifact qualification remains a separate gate.
|
|
119
|
+
|
|
120
|
+
### Added
|
|
121
|
+
|
|
122
|
+
- Version thread projection digests so v0.3.2/v0.3.3 cutover receipts keep verifying while new
|
|
123
|
+
projections carry the full diagnostic/compact shape; forged digests fail closed.
|
|
124
|
+
- Session snapshot sync state is decoupled from the Host transport: a Session snapshot failure
|
|
125
|
+
can no longer flip the live SSE to `replay-required`; Composer and command gates require both
|
|
126
|
+
transport live and the foreground Session snapshot ready.
|
|
127
|
+
- Host and browser diagnostics counters for Session switches, snapshot cache hits/loads/latency,
|
|
128
|
+
and Session actor allocation/eviction/closure, so "pure selection allocates no Runtime" is
|
|
129
|
+
provable from counters instead of prose.
|
|
130
|
+
- Runtime ownership across Workspace Context switches: the Host-level Session registry is created
|
|
131
|
+
once and preserved; control planes and Session actors borrow per-Workspace shared kernels, and
|
|
132
|
+
only Host shutdown closes every actor and kernel.
|
|
133
|
+
|
|
134
|
+
### Changed
|
|
135
|
+
|
|
136
|
+
- Instant Session switching renders a cached projection immediately, refreshes with a bounded
|
|
137
|
+
tail snapshot in the background, and prefetches the most recent Sessions after a baseline.
|
|
138
|
+
- Version and release hygiene: package identity moves to 0.3.5, `release:check` recognizes
|
|
139
|
+
`codex/vX.Y.Z` and `GITHUB_HEAD_REF` release branches, and the Web rail no longer falls back to
|
|
140
|
+
a hardcoded version string.
|
|
141
|
+
|
|
142
|
+
### Fixed
|
|
143
|
+
|
|
144
|
+
- Workspace Context activation no longer shuts down resident Session actors of other Workspaces
|
|
145
|
+
or requires every actor to be idle before switching the active control plane.
|
|
146
|
+
- A failed Context activation restores the previous control plane without rebuilding the Session
|
|
147
|
+
registry, so resident actors and their Runtime revisions survive the rollback.
|
|
148
|
+
|
|
25
149
|
## [0.3.4] — CANDIDATE
|
|
26
150
|
|
|
27
151
|
> **Status: candidate.** This stabilization work is isolated on the v0.3.4 worktree. It is not
|
package/README.md
CHANGED
|
@@ -2,11 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
Local-first, goal-driven coding agent for the terminal and browser.
|
|
4
4
|
|
|
5
|
-
> v0.3.
|
|
6
|
-
>
|
|
7
|
-
>
|
|
5
|
+
> v0.3.7 candidate — a left project-rail interaction release on top of the v0.3.6 work:
|
|
6
|
+
> shortened connection copy, a keyboard-reachable per-Session overflow menu
|
|
7
|
+
> (rename / tags / archive / delete with confirmation), persisted Session tags with
|
|
8
|
+
> rail badges, an archived-Session section with restore, and a friendlier
|
|
9
|
+
> "打开或新增项目" workspace dialog. Candidate source is not an npm publication,
|
|
10
|
+
> Git tag, or merge-ready release.
|
|
8
11
|
|
|
9
12
|
[中文说明](README.zh-CN.md) ·
|
|
13
|
+
[v0.3.7 plan](docs/plan/v0.3.7-left-rail-improvement-plan.md) ·
|
|
14
|
+
[v0.3.6 plan](docs/plan/v0.3.6-plan.md) ·
|
|
15
|
+
[v0.3.5 plan](docs/plan/v0.3.5-plan.md) ·
|
|
10
16
|
[v0.3.4 stabilization plan](docs/plan/v0.3.4-stabilization-plan.md) ·
|
|
11
17
|
[v0.3.4 contract](docs/architecture/v0.3.4-stabilization-contract.md) ·
|
|
12
18
|
[v0.3.4 E2E plan](docs/test/v0.3.4-stabilization-e2e-plan.md) ·
|
|
@@ -24,6 +30,56 @@ Local-first, goal-driven coding agent for the terminal and browser.
|
|
|
24
30
|
[Settings migration](docs/migration/v0.2.2-to-v0.3.0-settings.md) ·
|
|
25
31
|
[real-state gallery](docs/assets/screenshots/v0.3.0-web/README.md)
|
|
26
32
|
|
|
33
|
+
## What v0.3.7 changes
|
|
34
|
+
|
|
35
|
+
- **Left rail status copy** is shortened (已连接 / 离线 / …) with full sentences on hover.
|
|
36
|
+
- **Per-Session overflow menu** replaces the rename icon — 重命名… / 管理标签… / 归档 /
|
|
37
|
+
删除…, fully keyboard navigable, deleting requires an explicit confirmation dialog.
|
|
38
|
+
- **Session tags**: up to 8 persisted tags per Session, edited as chips and shown as
|
|
39
|
+
badges on rows; archive hides a Session (all files kept) into a rail 已归档 section
|
|
40
|
+
with one-click restore.
|
|
41
|
+
- **Workspace dialog** rework: "打开或新增项目" with suggested workspaces, a collapsible
|
|
42
|
+
"其他工作区" list and busy/validation feedback.
|
|
43
|
+
|
|
44
|
+
## What v0.3.6 changes
|
|
45
|
+
|
|
46
|
+
- **A component-rendering contract layer.** Six `.test.tsx` suites (89 cases) assert the web
|
|
47
|
+
workbench UI through `renderToStaticMarkup` — no jsdom needed — pinning Markdown tables and
|
|
48
|
+
headings, status dots, the shortcut help dialog, the diff viewer, the permission card and the
|
|
49
|
+
resize separator keyboard contract.
|
|
50
|
+
- **Keyboard-reachable resize separators.** Project navigation and work-panel splitters expose
|
|
51
|
+
full separator semantics (`aria-valuenow`/`aria-valuetext`) and answer ←/→ (±2%, Shift ±10%),
|
|
52
|
+
Home/End and Enter/Space from the keyboard.
|
|
53
|
+
- **Status without colour alone.** A shared `StateDot` adds a shape channel (`data-tone`) and a
|
|
54
|
+
screen-reader label to every status dot — reasoning, research sources, review evidence and the
|
|
55
|
+
work-panel rail.
|
|
56
|
+
- **Single-source shortcut help.** `⌘/` opens a help dialog rendered from the same binding table
|
|
57
|
+
the live handlers match against.
|
|
58
|
+
- **Theme cycle in the header.** One click walks system → light → dark and persists through the
|
|
59
|
+
settings document; light tokens stay consolidated in the blocksmith token sheet.
|
|
60
|
+
- **Stacked notifications.** Toasts queue instead of overwriting, auto-dismiss after 5s unless
|
|
61
|
+
error/recovery, and grade `aria-live` by severity.
|
|
62
|
+
|
|
63
|
+
## What v0.3.5 changes
|
|
64
|
+
|
|
65
|
+
- **Session snapshot state is its own machine.** A failed HTTP snapshot marks only the foreground
|
|
66
|
+
Session `failed` and never flips the live SSE into `replay-required`; Composer and command gates
|
|
67
|
+
require both a live transport and a ready foreground Session snapshot.
|
|
68
|
+
- **Instant Session switching.** A cached projection renders synchronously, a bounded tail snapshot
|
|
69
|
+
refreshes it in the background, the most recent Sessions are prefetched after a baseline, and stale
|
|
70
|
+
responses can never overwrite the browser-local foreground.
|
|
71
|
+
- **Runtime ownership across Workspaces.** The Host-level Session actor registry is created once per
|
|
72
|
+
Host. A Workspace Context switch swaps only the active control plane; Session actors of other
|
|
73
|
+
Workspaces keep running on the Workspace kernel they were created with, and only Host shutdown
|
|
74
|
+
closes every actor and kernel. Failed switches roll back without rebuilding the registry.
|
|
75
|
+
- **Provable runtime ownership.** Host and browser diagnostics count Session snapshot requests,
|
|
76
|
+
latency and failures, Session switches and cache hits, and actor allocation/eviction/closure — so a
|
|
77
|
+
pure selection provably allocates zero Session Runtimes.
|
|
78
|
+
- **Release hygiene.** Version identity moves to 0.3.5; `release:check` understands `codex/vX.Y.Z`
|
|
79
|
+
and `GITHUB_HEAD_REF`; the Web rail no longer hardcodes a fallback version.
|
|
80
|
+
|
|
81
|
+
This branch also carries the merged [v0.3.4 stabilization](#what-v034-stabilizes) below.
|
|
82
|
+
|
|
27
83
|
## What v0.3.4 stabilizes
|
|
28
84
|
|
|
29
85
|
- **Context-bound writes.** Settings mutations now carry the active Workspace and Context revision;
|
|
@@ -113,10 +169,10 @@ user extension boundaries.
|
|
|
113
169
|
Node.js 22.12+, 24, and 26 are supported. Use Node 24 LTS for production or Node 26 Current for
|
|
114
170
|
current development environments. Node 20 is upstream EOL and is no longer a v0.3 runtime.
|
|
115
171
|
|
|
116
|
-
After the immutable `0.3.
|
|
172
|
+
After the immutable `0.3.5` npm receipt exists:
|
|
117
173
|
|
|
118
174
|
```bash
|
|
119
|
-
npm install -g @orion-agents/orion-code@0.3.
|
|
175
|
+
npm install -g @orion-agents/orion-code@0.3.7
|
|
120
176
|
orion --version
|
|
121
177
|
orion doctor
|
|
122
178
|
```
|
package/README.zh-CN.md
CHANGED
|
@@ -2,10 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
面向终端与浏览器、本地优先的目标驱动 Coding Agent。
|
|
4
4
|
|
|
5
|
-
> v0.3.
|
|
6
|
-
>
|
|
5
|
+
> v0.3.7 候选版本:左侧项目栏交互发布(基于 v0.3.6 之上)—— 状态文案精简、会话行键盘可达
|
|
6
|
+
> 操作菜单(重命名 / 标签 / 归档 / 删除含确认)、可持久化会话标签与行内徽章、已归档会话区一键还原、
|
|
7
|
+
> 以及更友好的「打开或新增项目」工作区对话框。Candidate 源码不代表已创建 npm 发布、Git tag 或达到
|
|
8
|
+
> 可合并状态。
|
|
7
9
|
|
|
8
10
|
[English](README.md) ·
|
|
11
|
+
[v0.3.7 方案](docs/plan/v0.3.7-left-rail-improvement-plan.md) ·
|
|
12
|
+
[v0.3.6 方案](docs/plan/v0.3.6-plan.md) ·
|
|
9
13
|
[v0.3.4 稳定化方案](docs/plan/v0.3.4-stabilization-plan.md) ·
|
|
10
14
|
[v0.3.4 合同](docs/architecture/v0.3.4-stabilization-contract.md) ·
|
|
11
15
|
[v0.3.4 E2E 方案](docs/test/v0.3.4-stabilization-e2e-plan.md) ·
|
|
@@ -98,7 +102,7 @@ Current。Node 20 已结束上游维护,不再属于 v0.3 Runtime 合同。
|
|
|
98
102
|
当 npm 已存在不可变的 `0.3.4` 发布凭据后:
|
|
99
103
|
|
|
100
104
|
```bash
|
|
101
|
-
npm install -g @orion-agents/orion-code@0.3.
|
|
105
|
+
npm install -g @orion-agents/orion-code@0.3.7
|
|
102
106
|
orion --version
|
|
103
107
|
orion doctor
|
|
104
108
|
```
|
|
@@ -206,11 +206,7 @@ async function showHarness(ctx, args = '') {
|
|
|
206
206
|
},
|
|
207
207
|
};
|
|
208
208
|
const result = () => ({ success: true, output: lines.join('\n') });
|
|
209
|
-
const tokens = args
|
|
210
|
-
.trim()
|
|
211
|
-
.toLowerCase()
|
|
212
|
-
.split(/\s+/u)
|
|
213
|
-
.filter(Boolean);
|
|
209
|
+
const tokens = args.trim().toLowerCase().split(/\s+/u).filter(Boolean);
|
|
214
210
|
const explain = tokens[0] === 'explain';
|
|
215
211
|
const json = tokens.includes('--json');
|
|
216
212
|
if (tokens.some(token => token !== 'explain' && token !== '--json')) {
|
|
@@ -448,10 +448,7 @@ function registerBuiltinCommands(definitions) {
|
|
|
448
448
|
if (ids.has(command.id))
|
|
449
449
|
throw new Error(`Duplicate command id: ${command.id}`);
|
|
450
450
|
ids.add(command.id);
|
|
451
|
-
for (const value of [
|
|
452
|
-
command.name,
|
|
453
|
-
...(command.aliases ?? []),
|
|
454
|
-
]) {
|
|
451
|
+
for (const value of [command.name, ...(command.aliases ?? [])]) {
|
|
455
452
|
const normalized = value.toLowerCase();
|
|
456
453
|
const owner = names.get(normalized);
|
|
457
454
|
if (owner)
|
package/dist/harness/intent.js
CHANGED
|
@@ -38,14 +38,24 @@ function extractTools(input) {
|
|
|
38
38
|
return known.filter(tool => lower.includes(tool.toLowerCase()));
|
|
39
39
|
}
|
|
40
40
|
function extractConstraints(input) {
|
|
41
|
-
const lines = input
|
|
41
|
+
const lines = input
|
|
42
|
+
.split(/\r?\n/)
|
|
43
|
+
.map(line => line.trim())
|
|
44
|
+
.filter(Boolean);
|
|
42
45
|
const constraintPattern = /(必须|要求|确保|保持|不要|不能|不准|避免|只|仅|must|should|required|ensure|keep|avoid|without|do not|don't|never|only)/i;
|
|
43
|
-
return [
|
|
46
|
+
return [
|
|
47
|
+
...new Set(lines.filter(line => constraintPattern.test(line)).map(line => truncate(line, 180))),
|
|
48
|
+
].slice(0, 10);
|
|
44
49
|
}
|
|
45
50
|
function extractNonGoals(input) {
|
|
46
|
-
const lines = input
|
|
51
|
+
const lines = input
|
|
52
|
+
.split(/\r?\n/)
|
|
53
|
+
.map(line => line.trim())
|
|
54
|
+
.filter(Boolean);
|
|
47
55
|
const nonGoalPattern = /(不要|不能|不准|避免|不引入|不新增|禁止|do not|don't|never|avoid|without)/i;
|
|
48
|
-
return [
|
|
56
|
+
return [
|
|
57
|
+
...new Set(lines.filter(line => nonGoalPattern.test(line)).map(line => truncate(line, 180))),
|
|
58
|
+
].slice(0, 8);
|
|
49
59
|
}
|
|
50
60
|
function extractQuestions(input) {
|
|
51
61
|
return input
|
|
@@ -75,45 +85,86 @@ function classifyKind(input, state) {
|
|
|
75
85
|
return { kind: 'casual_or_feedback', confidence: 0.5, reason: 'empty input' };
|
|
76
86
|
}
|
|
77
87
|
if (isGenericContinue(text)) {
|
|
78
|
-
return {
|
|
88
|
+
return {
|
|
89
|
+
kind: 'continue_current_task',
|
|
90
|
+
confidence: 0.78,
|
|
91
|
+
reason: 'generic continuation request',
|
|
92
|
+
};
|
|
79
93
|
}
|
|
80
94
|
if (isShortFeedback(text)) {
|
|
81
|
-
return {
|
|
95
|
+
return {
|
|
96
|
+
kind: 'casual_or_feedback',
|
|
97
|
+
confidence: 0.72,
|
|
98
|
+
reason: 'short feedback should not replace the root objective',
|
|
99
|
+
};
|
|
82
100
|
}
|
|
83
|
-
if (matches(lower, /\b(verify|test|run tests?|check|lint|typecheck|build)\b/) ||
|
|
101
|
+
if (matches(lower, /\b(verify|test|run tests?|check|lint|typecheck|build)\b/) ||
|
|
102
|
+
matches(text, /(验证|测试|检查|跑一下|运行测试|构建|编译)/)) {
|
|
84
103
|
return { kind: 'verify_or_test', confidence: 0.82, reason: 'verification-oriented wording' };
|
|
85
104
|
}
|
|
86
105
|
if (hasRoot && isVersionScopedRefinement(text)) {
|
|
87
|
-
return {
|
|
106
|
+
return {
|
|
107
|
+
kind: 'refine_current_task',
|
|
108
|
+
confidence: 0.78,
|
|
109
|
+
reason: 'version-scoped refinement within the active task',
|
|
110
|
+
};
|
|
88
111
|
}
|
|
89
112
|
if (matches(lower, /\b(harness|mcp|session|resume|compact|config|configuration|ui|npm|publish|push|pull request|pr)\b/) ||
|
|
90
113
|
matches(text, /(配置|会话|恢复|压缩|版本|分支|发布|新ui|界面|工具|权限|确认|配置文件)/)) {
|
|
91
114
|
if (matches(text, /(基于当前|切\s*v|切到|这个版本|新版本|开始按|完整开发|实现这个方案)/) ||
|
|
92
115
|
matches(lower, /\b(please implement|implement this plan|start implementing|new version)\b/)) {
|
|
93
|
-
return {
|
|
116
|
+
return {
|
|
117
|
+
kind: 'new_task',
|
|
118
|
+
confidence: 0.88,
|
|
119
|
+
reason: 'explicit versioned implementation task',
|
|
120
|
+
};
|
|
94
121
|
}
|
|
95
|
-
return {
|
|
122
|
+
return {
|
|
123
|
+
kind: 'meta_configuration',
|
|
124
|
+
confidence: 0.75,
|
|
125
|
+
reason: 'configuration or CLI meta request',
|
|
126
|
+
};
|
|
96
127
|
}
|
|
97
128
|
if (matches(text, /(不对|不是|错了|改成|改为|换成|重新|重做|不要.+而是|应该.+而不是)/) ||
|
|
98
129
|
matches(lower, /\b(instead|replace|switch to|redo|wrong)\b/)) {
|
|
99
|
-
return {
|
|
130
|
+
return {
|
|
131
|
+
kind: 'interrupt_and_replace_current_step',
|
|
132
|
+
confidence: 0.8,
|
|
133
|
+
reason: 'correction or replacement wording',
|
|
134
|
+
};
|
|
100
135
|
}
|
|
101
136
|
if (matches(text, /(基于|切到|这个版本|新版本|开始|实现|开发|生成|创建|写文档|完成本次|按这个计划|完整支持|帮我完成)/) ||
|
|
102
137
|
matches(lower, /\b(generate|create|implement|build|start|complete this|write a|please implement)\b/)) {
|
|
103
|
-
return {
|
|
138
|
+
return {
|
|
139
|
+
kind: 'new_task',
|
|
140
|
+
confidence: hasRoot ? 0.76 : 0.86,
|
|
141
|
+
reason: 'explicit task creation wording',
|
|
142
|
+
};
|
|
104
143
|
}
|
|
105
144
|
// Clarification: user is asking for explanation or asking about meaning
|
|
106
145
|
// Must be checked BEFORE refinement since clarification phrases may contain "这个"
|
|
107
146
|
if (matches(text, /(什么意思|解释一下|解释说明|clarify|explain to me|what does.*mean|what is.*for|can you explain|meaning of)/) ||
|
|
108
147
|
matches(lower, /^(what|why|how|explain|clarify|could you explain|can you explain)\b/)) {
|
|
109
|
-
return {
|
|
148
|
+
return {
|
|
149
|
+
kind: 'clarification',
|
|
150
|
+
confidence: 0.7,
|
|
151
|
+
reason: 'clarification or explanation request',
|
|
152
|
+
};
|
|
110
153
|
}
|
|
111
154
|
if (matches(text, /(补充|另外|同时|还有|希望|可以|顺便|完善|优化|灰色|填充|这个|这里|如图|也|继续)/) ||
|
|
112
155
|
matches(lower, /\b(also|additionally|please also|refine|improve|continue)\b/)) {
|
|
113
|
-
return {
|
|
156
|
+
return {
|
|
157
|
+
kind: 'refine_current_task',
|
|
158
|
+
confidence: hasRoot ? 0.76 : 0.58,
|
|
159
|
+
reason: 'refinement or addition wording',
|
|
160
|
+
};
|
|
114
161
|
}
|
|
115
162
|
return hasRoot
|
|
116
|
-
? {
|
|
163
|
+
? {
|
|
164
|
+
kind: 'refine_current_task',
|
|
165
|
+
confidence: 0.55,
|
|
166
|
+
reason: 'existing task makes ambiguous input a refinement',
|
|
167
|
+
}
|
|
117
168
|
: { kind: 'new_task', confidence: 0.62, reason: 'first meaningful user task' };
|
|
118
169
|
}
|
|
119
170
|
function classifyIntent(input, state) {
|
|
@@ -121,7 +172,9 @@ function classifyIntent(input, state) {
|
|
|
121
172
|
const baseEpoch = state?.taskEpoch ?? (state?.contract ? 1 : 0);
|
|
122
173
|
const classified = classifyKind(input, state);
|
|
123
174
|
const rootObjectiveChanged = classified.kind === 'new_task' || !state?.contract;
|
|
124
|
-
const taskEpoch = rootObjectiveChanged
|
|
175
|
+
const taskEpoch = rootObjectiveChanged
|
|
176
|
+
? Math.max(1, baseEpoch + (state?.contract ? 1 : 0))
|
|
177
|
+
: Math.max(1, baseEpoch || 1);
|
|
125
178
|
const summary = truncate(input || 'Continue the current task');
|
|
126
179
|
return {
|
|
127
180
|
id: (0, crypto_1.randomUUID)(),
|
|
@@ -12,7 +12,9 @@ function unique(items) {
|
|
|
12
12
|
function parseJsonObject(text) {
|
|
13
13
|
try {
|
|
14
14
|
const parsed = JSON.parse(text);
|
|
15
|
-
return parsed && typeof parsed === 'object' && !Array.isArray(parsed)
|
|
15
|
+
return parsed && typeof parsed === 'object' && !Array.isArray(parsed)
|
|
16
|
+
? parsed
|
|
17
|
+
: null;
|
|
16
18
|
}
|
|
17
19
|
catch {
|
|
18
20
|
return null;
|
|
@@ -100,7 +100,7 @@ class EmbeddingService {
|
|
|
100
100
|
input: text,
|
|
101
101
|
}, {
|
|
102
102
|
headers: {
|
|
103
|
-
|
|
103
|
+
Authorization: `Bearer ${apiKey}`,
|
|
104
104
|
'Content-Type': 'application/json',
|
|
105
105
|
},
|
|
106
106
|
timeout: 30000,
|
|
@@ -121,8 +121,7 @@ let defaultService = null;
|
|
|
121
121
|
function getEmbeddingService(config) {
|
|
122
122
|
if (!defaultService) {
|
|
123
123
|
// Auto-detect provider from environment
|
|
124
|
-
const provider = process.env[environment_1.ENV.EMBEDDING_PROVIDER] ||
|
|
125
|
-
(process.env.OLLAMA_BASE_URL ? 'ollama' : 'openai');
|
|
124
|
+
const provider = process.env[environment_1.ENV.EMBEDDING_PROVIDER] || (process.env.OLLAMA_BASE_URL ? 'ollama' : 'openai');
|
|
126
125
|
defaultService = new EmbeddingService({
|
|
127
126
|
provider: provider,
|
|
128
127
|
model: process.env[environment_1.ENV.EMBEDDING_MODEL],
|
package/dist/memory/prompts.js
CHANGED
|
@@ -24,7 +24,7 @@ function buildMemoryPrompt() {
|
|
|
24
24
|
'This directory already exists — write to it directly with the Write tool.',
|
|
25
25
|
'',
|
|
26
26
|
'You should build up this memory system over time so that future conversations',
|
|
27
|
-
|
|
27
|
+
"can have a complete picture of who the user is, how they'd like to collaborate,",
|
|
28
28
|
'what behaviors to avoid or repeat, and the context behind the work.',
|
|
29
29
|
'',
|
|
30
30
|
'If the user explicitly asks you to remember something, save it immediately.',
|
|
@@ -38,20 +38,128 @@ function extractKeywords(text, preserveCase = false) {
|
|
|
38
38
|
.filter(w => w.length >= 2);
|
|
39
39
|
// 去除常见停用词
|
|
40
40
|
const stopWords = new Set([
|
|
41
|
-
'the',
|
|
42
|
-
'
|
|
43
|
-
'
|
|
44
|
-
'
|
|
45
|
-
'
|
|
46
|
-
'
|
|
47
|
-
'
|
|
48
|
-
'
|
|
49
|
-
'
|
|
50
|
-
'
|
|
51
|
-
'
|
|
52
|
-
'
|
|
53
|
-
'
|
|
54
|
-
'
|
|
41
|
+
'the',
|
|
42
|
+
'a',
|
|
43
|
+
'an',
|
|
44
|
+
'and',
|
|
45
|
+
'or',
|
|
46
|
+
'but',
|
|
47
|
+
'in',
|
|
48
|
+
'on',
|
|
49
|
+
'at',
|
|
50
|
+
'to',
|
|
51
|
+
'for',
|
|
52
|
+
'of',
|
|
53
|
+
'with',
|
|
54
|
+
'by',
|
|
55
|
+
'from',
|
|
56
|
+
'as',
|
|
57
|
+
'is',
|
|
58
|
+
'was',
|
|
59
|
+
'are',
|
|
60
|
+
'were',
|
|
61
|
+
'been',
|
|
62
|
+
'be',
|
|
63
|
+
'have',
|
|
64
|
+
'has',
|
|
65
|
+
'had',
|
|
66
|
+
'do',
|
|
67
|
+
'does',
|
|
68
|
+
'did',
|
|
69
|
+
'will',
|
|
70
|
+
'would',
|
|
71
|
+
'could',
|
|
72
|
+
'should',
|
|
73
|
+
'may',
|
|
74
|
+
'might',
|
|
75
|
+
'must',
|
|
76
|
+
'can',
|
|
77
|
+
'this',
|
|
78
|
+
'that',
|
|
79
|
+
'these',
|
|
80
|
+
'those',
|
|
81
|
+
'it',
|
|
82
|
+
'its',
|
|
83
|
+
'they',
|
|
84
|
+
'them',
|
|
85
|
+
'their',
|
|
86
|
+
'we',
|
|
87
|
+
'our',
|
|
88
|
+
'you',
|
|
89
|
+
'your',
|
|
90
|
+
'he',
|
|
91
|
+
'him',
|
|
92
|
+
'his',
|
|
93
|
+
'she',
|
|
94
|
+
'her',
|
|
95
|
+
'i',
|
|
96
|
+
'me',
|
|
97
|
+
'my',
|
|
98
|
+
'not',
|
|
99
|
+
'no',
|
|
100
|
+
'yes',
|
|
101
|
+
'all',
|
|
102
|
+
'any',
|
|
103
|
+
'some',
|
|
104
|
+
'each',
|
|
105
|
+
'every',
|
|
106
|
+
'both',
|
|
107
|
+
'few',
|
|
108
|
+
'many',
|
|
109
|
+
'more',
|
|
110
|
+
'most',
|
|
111
|
+
'other',
|
|
112
|
+
'another',
|
|
113
|
+
'such',
|
|
114
|
+
'only',
|
|
115
|
+
'own',
|
|
116
|
+
'same',
|
|
117
|
+
'so',
|
|
118
|
+
'than',
|
|
119
|
+
'too',
|
|
120
|
+
'very',
|
|
121
|
+
'just',
|
|
122
|
+
'also',
|
|
123
|
+
'now',
|
|
124
|
+
'then',
|
|
125
|
+
'here',
|
|
126
|
+
'there',
|
|
127
|
+
'when',
|
|
128
|
+
'where',
|
|
129
|
+
'why',
|
|
130
|
+
'how',
|
|
131
|
+
'what',
|
|
132
|
+
'which',
|
|
133
|
+
'who',
|
|
134
|
+
'whom',
|
|
135
|
+
'whose',
|
|
136
|
+
'if',
|
|
137
|
+
'else',
|
|
138
|
+
'then',
|
|
139
|
+
'because',
|
|
140
|
+
'since',
|
|
141
|
+
'although',
|
|
142
|
+
'though',
|
|
143
|
+
'while',
|
|
144
|
+
'during',
|
|
145
|
+
'before',
|
|
146
|
+
'after',
|
|
147
|
+
'until',
|
|
148
|
+
'above',
|
|
149
|
+
'below',
|
|
150
|
+
'between',
|
|
151
|
+
'under',
|
|
152
|
+
'over',
|
|
153
|
+
'out',
|
|
154
|
+
'into',
|
|
155
|
+
'onto',
|
|
156
|
+
'about',
|
|
157
|
+
'against',
|
|
158
|
+
'through',
|
|
159
|
+
'across',
|
|
160
|
+
'along',
|
|
161
|
+
'around',
|
|
162
|
+
'again',
|
|
55
163
|
]);
|
|
56
164
|
// 停用词过滤始终大小写不敏感,否则 preserveCase 模式下 "The"/"And" 会漏过。
|
|
57
165
|
return words.filter(w => !stopWords.has(preserveCase ? w.toLowerCase() : w));
|
|
@@ -84,7 +192,9 @@ function calculateKeywordMatch(queryKeywords, memoryEntry, caseSensitive = false
|
|
|
84
192
|
for (const mk of memoryKeywords) {
|
|
85
193
|
const compareMk = caseSensitive ? mk : mk.toLowerCase();
|
|
86
194
|
// 精确匹配或部分匹配(包含关系)
|
|
87
|
-
if (compareMk === compareQk ||
|
|
195
|
+
if (compareMk === compareQk ||
|
|
196
|
+
compareMk.includes(compareQk) ||
|
|
197
|
+
compareQk.includes(compareMk)) {
|
|
88
198
|
matchedKeywords.push(qk);
|
|
89
199
|
matchCount++;
|
|
90
200
|
break;
|