@orion-agents/orion-code 0.3.4 → 0.3.9
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 +157 -0
- package/README.md +59 -5
- package/README.zh-CN.md +6 -3
- package/dist/cli.js +58 -32
- 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/redaction.js +8 -0
- 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/cli-options.d.ts +13 -0
- package/dist/web/cli-options.js +47 -0
- package/dist/web/host-daemon.d.ts +61 -0
- package/dist/web/host-daemon.js +193 -0
- package/dist/web/launch.d.ts +3 -0
- package/dist/web/launch.js +24 -0
- package/dist/web/protocol.d.ts +2 -0
- package/dist/web/protocol.js +1 -0
- package/dist/web/review-service.js +41 -13
- 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-MMhvMif-.js} +1 -1
- package/dist/web-client/assets/{FilesPanel-CCDoAZ1J.js → FilesPanel-4litEN1k.js} +1 -1
- package/dist/web-client/assets/{GitPanel-DtNgiH7A.js → GitPanel-BVwlDRVo.js} +1 -1
- package/dist/web-client/assets/ReviewPanel-ChA0Zd2g.js +1 -0
- package/dist/web-client/assets/{TerminalPanel-CNxMaBLp.js → TerminalPanel-D8C1uybv.js} +1 -1
- package/dist/web-client/assets/index-DQfpqPTD.css +1 -0
- package/dist/web-client/assets/index-Dv_uE9dk.js +17 -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
|
@@ -7,31 +7,181 @@ exports.getModelCatalogAliases = getModelCatalogAliases;
|
|
|
7
7
|
exports.getModelCatalogDiagnostics = getModelCatalogDiagnostics;
|
|
8
8
|
const model_context_1 = require("./model-context");
|
|
9
9
|
const MODEL_CATALOG = [
|
|
10
|
-
{
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
{
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
{
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
{
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
10
|
+
{
|
|
11
|
+
name: 'claude-opus-4-8',
|
|
12
|
+
alias: 'opus',
|
|
13
|
+
provider: 'Anthropic',
|
|
14
|
+
contextWindow: 200000,
|
|
15
|
+
maxOutputTokens: 32000,
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
name: 'claude-sonnet-4-6',
|
|
19
|
+
alias: 'sonnet',
|
|
20
|
+
provider: 'Anthropic',
|
|
21
|
+
contextWindow: 200000,
|
|
22
|
+
maxOutputTokens: 16000,
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
name: 'claude-haiku-4-5-20251001',
|
|
26
|
+
alias: 'haiku',
|
|
27
|
+
provider: 'Anthropic',
|
|
28
|
+
contextWindow: 200000,
|
|
29
|
+
maxOutputTokens: 8192,
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
name: 'gpt-4o',
|
|
33
|
+
alias: 'gpt4o',
|
|
34
|
+
provider: 'OpenAI',
|
|
35
|
+
contextWindow: 128000,
|
|
36
|
+
maxOutputTokens: 16384,
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: 'gpt-4o-mini',
|
|
40
|
+
alias: 'gpt4omin',
|
|
41
|
+
provider: 'OpenAI',
|
|
42
|
+
contextWindow: 128000,
|
|
43
|
+
maxOutputTokens: 16384,
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
name: 'gpt-3.5-turbo',
|
|
47
|
+
alias: 'gpt35',
|
|
48
|
+
provider: 'OpenAI',
|
|
49
|
+
contextWindow: 16385,
|
|
50
|
+
maxOutputTokens: 4096,
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: 'glm-5',
|
|
54
|
+
alias: 'glm',
|
|
55
|
+
provider: 'Bailian (Zhipu)',
|
|
56
|
+
contextWindow: 202752,
|
|
57
|
+
maxOutputTokens: 8192,
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: 'glm-4.7',
|
|
61
|
+
alias: 'glm47',
|
|
62
|
+
provider: 'Bailian (Zhipu)',
|
|
63
|
+
contextWindow: 131072,
|
|
64
|
+
maxOutputTokens: 8192,
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
name: 'glm-5.2',
|
|
68
|
+
alias: 'glm52',
|
|
69
|
+
provider: 'Huoshan (Volcengine)',
|
|
70
|
+
contextWindow: 1024000,
|
|
71
|
+
maxOutputTokens: 128000,
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
name: 'qwen3.7-plus',
|
|
75
|
+
alias: 'qwen',
|
|
76
|
+
provider: 'Bailian (Alibaba)',
|
|
77
|
+
contextWindow: 131072,
|
|
78
|
+
maxOutputTokens: 8192,
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: 'qwen3.6-plus',
|
|
82
|
+
alias: 'qwen36',
|
|
83
|
+
provider: 'Bailian (Alibaba)',
|
|
84
|
+
contextWindow: 131072,
|
|
85
|
+
maxOutputTokens: 8192,
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
name: 'qwen3.5-plus',
|
|
89
|
+
alias: 'qwen35',
|
|
90
|
+
provider: 'Bailian (Alibaba)',
|
|
91
|
+
contextWindow: 131072,
|
|
92
|
+
maxOutputTokens: 8192,
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
name: 'qwen3-max-2026-01-23',
|
|
96
|
+
alias: 'qwenmax',
|
|
97
|
+
provider: 'Bailian (Alibaba)',
|
|
98
|
+
contextWindow: 131072,
|
|
99
|
+
maxOutputTokens: 8192,
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
name: 'qwen3-coder-plus',
|
|
103
|
+
alias: 'coder',
|
|
104
|
+
provider: 'Bailian (Alibaba)',
|
|
105
|
+
contextWindow: 131072,
|
|
106
|
+
maxOutputTokens: 8192,
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
name: 'qwen3-coder-next',
|
|
110
|
+
alias: 'codernext',
|
|
111
|
+
provider: 'Bailian (Alibaba)',
|
|
112
|
+
contextWindow: 131072,
|
|
113
|
+
maxOutputTokens: 8192,
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
name: 'kimi-k2.5',
|
|
117
|
+
alias: 'kimi',
|
|
118
|
+
provider: 'Bailian (Moonshot)',
|
|
119
|
+
contextWindow: 131072,
|
|
120
|
+
maxOutputTokens: 8192,
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
name: 'kimi-k2.7-code',
|
|
124
|
+
alias: 'kimicode',
|
|
125
|
+
provider: 'Huoshan (Volcengine)',
|
|
126
|
+
contextWindow: 256000,
|
|
127
|
+
maxOutputTokens: 32768,
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
name: 'MiniMax-M2.5',
|
|
131
|
+
alias: 'minimax',
|
|
132
|
+
provider: 'Bailian (MiniMax)',
|
|
133
|
+
contextWindow: 131072,
|
|
134
|
+
maxOutputTokens: 8192,
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
name: 'ark-code-latest',
|
|
138
|
+
alias: 'ark',
|
|
139
|
+
provider: 'Huoshan (Volcengine)',
|
|
140
|
+
contextWindow: 1024000,
|
|
141
|
+
maxOutputTokens: 128000,
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
name: 'deepseek-v4-pro',
|
|
145
|
+
alias: 'dsv4pro',
|
|
146
|
+
provider: 'Huoshan (Volcengine)',
|
|
147
|
+
contextWindow: 1000000,
|
|
148
|
+
maxOutputTokens: 384000,
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
name: 'xopdeepseekv4pro',
|
|
152
|
+
alias: 'xdsv4pro',
|
|
153
|
+
provider: 'XF MAAS (xf-yun)',
|
|
154
|
+
contextWindow: 1000000,
|
|
155
|
+
maxOutputTokens: 16384,
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
name: 'xopglm51',
|
|
159
|
+
alias: 'xglm51',
|
|
160
|
+
provider: 'XF MAAS (xf-yun)',
|
|
161
|
+
contextWindow: 204800,
|
|
162
|
+
maxOutputTokens: 16384,
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
name: 'astron-code-latest',
|
|
166
|
+
alias: 'astron',
|
|
167
|
+
provider: 'XF MAAS (xf-yun)',
|
|
168
|
+
contextWindow: 92160,
|
|
169
|
+
maxOutputTokens: 32768,
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
name: 'deepseek-chat',
|
|
173
|
+
alias: 'dschat',
|
|
174
|
+
provider: 'DeepSeek',
|
|
175
|
+
contextWindow: 64000,
|
|
176
|
+
maxOutputTokens: 8192,
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
name: 'deepseek-coder',
|
|
180
|
+
alias: 'dscoder',
|
|
181
|
+
provider: 'DeepSeek',
|
|
182
|
+
contextWindow: 64000,
|
|
183
|
+
maxOutputTokens: 8192,
|
|
184
|
+
},
|
|
35
185
|
];
|
|
36
186
|
const EXTRA_ALIASES = {
|
|
37
187
|
claude: 'claude-sonnet-4-6',
|
|
@@ -46,7 +196,8 @@ function listModelCatalogEntries() {
|
|
|
46
196
|
}
|
|
47
197
|
function getModelCatalogEntry(modelIdOrAlias) {
|
|
48
198
|
const normalized = normalizeCatalogKey(modelIdOrAlias);
|
|
49
|
-
return MODEL_CATALOG.find(entry => normalizeCatalogKey(entry.name) === normalized ||
|
|
199
|
+
return MODEL_CATALOG.find(entry => normalizeCatalogKey(entry.name) === normalized ||
|
|
200
|
+
normalizeCatalogKey(entry.alias) === normalized);
|
|
50
201
|
}
|
|
51
202
|
function resolveModelAlias(modelIdOrAlias) {
|
|
52
203
|
const normalized = normalizeCatalogKey(modelIdOrAlias);
|
|
@@ -66,12 +217,10 @@ function getModelCatalogAliases() {
|
|
|
66
217
|
return { ...aliases, ...EXTRA_ALIASES };
|
|
67
218
|
}
|
|
68
219
|
function getModelCatalogDiagnostics() {
|
|
69
|
-
const unknownCatalogModels = MODEL_CATALOG
|
|
70
|
-
.filter(entry => {
|
|
220
|
+
const unknownCatalogModels = MODEL_CATALOG.filter(entry => {
|
|
71
221
|
const source = (0, model_context_1.resolveModelContext)(entry.name).source;
|
|
72
222
|
return source === 'default' || source === 'fuzzy';
|
|
73
|
-
})
|
|
74
|
-
.map(entry => entry.name);
|
|
223
|
+
}).map(entry => entry.name);
|
|
75
224
|
const unknownAliases = Object.entries(getModelCatalogAliases())
|
|
76
225
|
.filter(([, modelId]) => {
|
|
77
226
|
const source = (0, model_context_1.resolveModelContext)(modelId).source;
|
|
@@ -474,7 +474,7 @@ function resolveContextBudget(modelId, requestedOutputTokens) {
|
|
|
474
474
|
const model = resolveModelContext(modelId);
|
|
475
475
|
const requested = Number.isFinite(requestedOutputTokens)
|
|
476
476
|
? Math.max(0, Math.round(requestedOutputTokens ?? 0))
|
|
477
|
-
: model.maxOutputTokens ?? 8192;
|
|
477
|
+
: (model.maxOutputTokens ?? 8192);
|
|
478
478
|
// 输出预留最多占上下文窗口的一半:某些条目的 maxOutputTokens 等于(甚至接近)
|
|
479
479
|
// contextWindow,直接相减会把可用输入预算打到 0/负数。
|
|
480
480
|
const reservedCeiling = Math.max(1, Math.floor(model.contextWindow * exports.MAX_OUTPUT_RESERVE_RATIO));
|
|
@@ -24,9 +24,7 @@ function reconcileStreamOverlap(previousText, recoveryText, maxWindow = 2048) {
|
|
|
24
24
|
return { suffix: recoveryText, overlapFound: false, overlapText: '' };
|
|
25
25
|
}
|
|
26
26
|
// Only look at the tail of previousText within maxWindow.
|
|
27
|
-
const tail = previousText.length > maxWindow
|
|
28
|
-
? previousText.slice(-maxWindow)
|
|
29
|
-
: previousText;
|
|
27
|
+
const tail = previousText.length > maxWindow ? previousText.slice(-maxWindow) : previousText;
|
|
30
28
|
// Find longest suffix-prefix match.
|
|
31
29
|
let bestLen = 0;
|
|
32
30
|
for (let len = Math.min(tail.length, recoveryText.length); len > 0; len--) {
|
|
@@ -69,6 +69,14 @@ const SECRET_PATTERNS = [
|
|
|
69
69
|
// Anthropic / OpenAI-style long-lived keys that do not start with `sk-`.
|
|
70
70
|
[/\bxai-[A-Za-z0-9]{16,}\b/g, '[REDACTED_SECRET]'],
|
|
71
71
|
[/\bgsk_[A-Za-z0-9]{16,}\b/g, '[REDACTED_SECRET]'],
|
|
72
|
+
[
|
|
73
|
+
// Uppercase environment assignments with a secret-shaped suffix, e.g.
|
|
74
|
+
// `export X_CLIENT_SECRET=…` / `CLIENT_SECRET=…`. The generic lower-case
|
|
75
|
+
// field rules cannot match these because the underscore is a word
|
|
76
|
+
// character, so no boundary exists right before `client_secret` (issue #241).
|
|
77
|
+
/\b((?:[A-Z][A-Z0-9_]*_)?(?:CLIENT_SECRET|ACCESS_TOKEN|AUTH_TOKEN|SECRET_KEY|PRIVATE_KEY|SESSION_KEY|ENCRYPTION_KEY|DB_PASSWORD|API_KEY|API_TOKEN|CREDENTIALS?|SECRETS?)\s*=\s*)(["']?)[^\s"',;]+/gi,
|
|
78
|
+
'$1$2[REDACTED_SECRET]',
|
|
79
|
+
],
|
|
72
80
|
[/\bBearer\s+[A-Za-z0-9._~+/=-]{8,}/gi, 'Bearer [REDACTED_SECRET]'],
|
|
73
81
|
];
|
|
74
82
|
/** Field-name guard shared by browser/event and approval snapshot projections. */
|
|
@@ -71,6 +71,10 @@ export interface SessionMeta {
|
|
|
71
71
|
lastCompactAt?: number;
|
|
72
72
|
/** Optional human-readable name */
|
|
73
73
|
name?: string;
|
|
74
|
+
/** v0.3.7 — Optional user-assigned tags shown in the project rail (max 8, each ≤ 32 chars). */
|
|
75
|
+
tags?: string[];
|
|
76
|
+
/** v0.3.7 — Set when the session is archived; archived sessions are hidden from default listings. */
|
|
77
|
+
archivedAt?: number;
|
|
74
78
|
/** Git branch at session creation/resume time */
|
|
75
79
|
gitBranch?: string;
|
|
76
80
|
/** token 数 */
|
|
@@ -606,19 +610,27 @@ export declare function loadSessionHistoryWithDiagnostics(sessionId: string): Se
|
|
|
606
610
|
*/
|
|
607
611
|
export declare function loadSessionRestoreBundle(sessionId: string): SessionRestoreBundleV1;
|
|
608
612
|
/**
|
|
609
|
-
*
|
|
613
|
+
* 列出所有会话(不含已归档)
|
|
610
614
|
*/
|
|
611
615
|
export declare function listSessions(limit?: number): SessionMeta[];
|
|
612
616
|
/**
|
|
613
617
|
* Count catalogued Sessions by their canonical project identity without
|
|
614
618
|
* sorting or touching every project directory. This is the lightweight read
|
|
615
|
-
* model used by project pickers and other collection summaries.
|
|
619
|
+
* model used by project pickers and other collection summaries. Archived
|
|
620
|
+
* Sessions are excluded so the picker count matches the default listing.
|
|
616
621
|
*/
|
|
617
622
|
export declare function countSessionsByProject(): ReadonlyMap<string, number>;
|
|
618
623
|
/**
|
|
619
|
-
* List sessions for a single canonical project
|
|
624
|
+
* List sessions for a single canonical project (default listings exclude
|
|
625
|
+
* archived sessions).
|
|
620
626
|
*/
|
|
621
627
|
export declare function listProjectSessions(projectPath: string, limit?: number): SessionMeta[];
|
|
628
|
+
/**
|
|
629
|
+
* Archived sessions of a single project, newest archive first. Backed by the
|
|
630
|
+
* same catalog so `restoreSession`/`deleteSession` keep the two listings in
|
|
631
|
+
* sync.
|
|
632
|
+
*/
|
|
633
|
+
export declare function listArchivedProjectSessions(projectPath: string, limit?: number): SessionMeta[];
|
|
622
634
|
/**
|
|
623
635
|
* Find a session by full id, id prefix, or exact name. Project sessions are
|
|
624
636
|
* searched by default; pass allProjects when the user explicitly asks.
|
|
@@ -639,6 +651,19 @@ export declare function lookupSessionRefInSessions(ref: string, candidates: read
|
|
|
639
651
|
* Rename a session for easier picker/resume targeting.
|
|
640
652
|
*/
|
|
641
653
|
export declare function renameSession(sessionId: string, name: string): SessionMeta | null;
|
|
654
|
+
export declare const SESSION_TAG_LIMIT = 8;
|
|
655
|
+
export declare const SESSION_TAG_MAX_LENGTH = 32;
|
|
656
|
+
/** Normalize user-supplied tags: trim, drop empties, cap length and count, dedupe. */
|
|
657
|
+
export declare function normalizeSessionTags(tags: readonly string[]): string[];
|
|
658
|
+
/**
|
|
659
|
+
* Replace the user-assigned tag set. An empty result clears tags entirely.
|
|
660
|
+
* Returns `null` when the session no longer exists.
|
|
661
|
+
*/
|
|
662
|
+
export declare function setSessionTags(sessionId: string, tags: readonly string[]): SessionMeta | null;
|
|
663
|
+
/** Soft-delete: keeps every file but hides the session from default listings. */
|
|
664
|
+
export declare function archiveSession(sessionId: string): SessionMeta | null;
|
|
665
|
+
/** Bring an archived session back into the default listings. */
|
|
666
|
+
export declare function restoreSession(sessionId: string): SessionMeta | null;
|
|
642
667
|
/**
|
|
643
668
|
* 删除会话
|
|
644
669
|
*/
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* 参考 OpenClaude 的 history.jsonl 和 sessions/ 目录。
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.SessionComposerPreferencesConflictError = exports.SESSION_SIDECAR_SUFFIXES = exports.redactTraceText = void 0;
|
|
9
|
+
exports.SESSION_TAG_MAX_LENGTH = exports.SESSION_TAG_LIMIT = exports.SessionComposerPreferencesConflictError = exports.SESSION_SIDECAR_SUFFIXES = exports.redactTraceText = void 0;
|
|
10
10
|
exports.resolveProjectPath = resolveProjectPath;
|
|
11
11
|
exports.getProjectKey = getProjectKey;
|
|
12
12
|
exports.isSessionMetaFile = isSessionMetaFile;
|
|
@@ -54,10 +54,15 @@ exports.loadSessionRestoreBundle = loadSessionRestoreBundle;
|
|
|
54
54
|
exports.listSessions = listSessions;
|
|
55
55
|
exports.countSessionsByProject = countSessionsByProject;
|
|
56
56
|
exports.listProjectSessions = listProjectSessions;
|
|
57
|
+
exports.listArchivedProjectSessions = listArchivedProjectSessions;
|
|
57
58
|
exports.findSession = findSession;
|
|
58
59
|
exports.lookupSessionRef = lookupSessionRef;
|
|
59
60
|
exports.lookupSessionRefInSessions = lookupSessionRefInSessions;
|
|
60
61
|
exports.renameSession = renameSession;
|
|
62
|
+
exports.normalizeSessionTags = normalizeSessionTags;
|
|
63
|
+
exports.setSessionTags = setSessionTags;
|
|
64
|
+
exports.archiveSession = archiveSession;
|
|
65
|
+
exports.restoreSession = restoreSession;
|
|
61
66
|
exports.deleteSession = deleteSession;
|
|
62
67
|
const fs_1 = require("fs");
|
|
63
68
|
const crypto_1 = require("crypto");
|
|
@@ -2215,30 +2220,44 @@ function sessionMessageToModelMessage(message) {
|
|
|
2215
2220
|
return result;
|
|
2216
2221
|
}
|
|
2217
2222
|
/**
|
|
2218
|
-
*
|
|
2223
|
+
* 列出所有会话(不含已归档)
|
|
2219
2224
|
*/
|
|
2220
2225
|
function listSessions(limit) {
|
|
2221
|
-
const sessions = sortSessionsNewestFirst(Object.values(loadOrRebuildSessionCatalog().sessions));
|
|
2226
|
+
const sessions = sortSessionsNewestFirst(Object.values(loadOrRebuildSessionCatalog().sessions).filter(session => !session.archivedAt));
|
|
2222
2227
|
return limit ? sessions.slice(0, limit) : sessions;
|
|
2223
2228
|
}
|
|
2224
2229
|
/**
|
|
2225
2230
|
* Count catalogued Sessions by their canonical project identity without
|
|
2226
2231
|
* sorting or touching every project directory. This is the lightweight read
|
|
2227
|
-
* model used by project pickers and other collection summaries.
|
|
2232
|
+
* model used by project pickers and other collection summaries. Archived
|
|
2233
|
+
* Sessions are excluded so the picker count matches the default listing.
|
|
2228
2234
|
*/
|
|
2229
2235
|
function countSessionsByProject() {
|
|
2230
2236
|
const counts = new Map();
|
|
2231
2237
|
for (const session of Object.values(loadOrRebuildSessionCatalog().sessions)) {
|
|
2238
|
+
if (session.archivedAt)
|
|
2239
|
+
continue;
|
|
2232
2240
|
counts.set(session.projectPath, (counts.get(session.projectPath) ?? 0) + 1);
|
|
2233
2241
|
}
|
|
2234
2242
|
return counts;
|
|
2235
2243
|
}
|
|
2236
2244
|
/**
|
|
2237
|
-
* List sessions for a single canonical project
|
|
2245
|
+
* List sessions for a single canonical project (default listings exclude
|
|
2246
|
+
* archived sessions).
|
|
2238
2247
|
*/
|
|
2239
2248
|
function listProjectSessions(projectPath, limit) {
|
|
2240
2249
|
const canonicalProjectPath = resolveProjectPath(projectPath);
|
|
2241
|
-
const sessions = sortSessionsNewestFirst(Object.values(loadOrRebuildSessionCatalog().sessions).filter(session => session.projectPath === canonicalProjectPath));
|
|
2250
|
+
const sessions = sortSessionsNewestFirst(Object.values(loadOrRebuildSessionCatalog().sessions).filter(session => session.projectPath === canonicalProjectPath && !session.archivedAt));
|
|
2251
|
+
return limit ? sessions.slice(0, limit) : sessions;
|
|
2252
|
+
}
|
|
2253
|
+
/**
|
|
2254
|
+
* Archived sessions of a single project, newest archive first. Backed by the
|
|
2255
|
+
* same catalog so `restoreSession`/`deleteSession` keep the two listings in
|
|
2256
|
+
* sync.
|
|
2257
|
+
*/
|
|
2258
|
+
function listArchivedProjectSessions(projectPath, limit) {
|
|
2259
|
+
const canonicalProjectPath = resolveProjectPath(projectPath);
|
|
2260
|
+
const sessions = sortSessionsNewestFirst(Object.values(loadOrRebuildSessionCatalog().sessions).filter(session => session.projectPath === canonicalProjectPath && (session.archivedAt ?? 0) > 0));
|
|
2242
2261
|
return limit ? sessions.slice(0, limit) : sessions;
|
|
2243
2262
|
}
|
|
2244
2263
|
/**
|
|
@@ -2292,6 +2311,51 @@ function renameSession(sessionId, name) {
|
|
|
2292
2311
|
session.updatedAtIso = new Date(session.updatedAt).toISOString();
|
|
2293
2312
|
});
|
|
2294
2313
|
}
|
|
2314
|
+
exports.SESSION_TAG_LIMIT = 8;
|
|
2315
|
+
exports.SESSION_TAG_MAX_LENGTH = 32;
|
|
2316
|
+
/** Normalize user-supplied tags: trim, drop empties, cap length and count, dedupe. */
|
|
2317
|
+
function normalizeSessionTags(tags) {
|
|
2318
|
+
const seen = new Set();
|
|
2319
|
+
const normalized = [];
|
|
2320
|
+
for (const raw of tags) {
|
|
2321
|
+
const tag = raw.trim().slice(0, exports.SESSION_TAG_MAX_LENGTH);
|
|
2322
|
+
if (!tag || seen.has(tag))
|
|
2323
|
+
continue;
|
|
2324
|
+
seen.add(tag);
|
|
2325
|
+
normalized.push(tag);
|
|
2326
|
+
if (normalized.length >= exports.SESSION_TAG_LIMIT)
|
|
2327
|
+
break;
|
|
2328
|
+
}
|
|
2329
|
+
return normalized;
|
|
2330
|
+
}
|
|
2331
|
+
/**
|
|
2332
|
+
* Replace the user-assigned tag set. An empty result clears tags entirely.
|
|
2333
|
+
* Returns `null` when the session no longer exists.
|
|
2334
|
+
*/
|
|
2335
|
+
function setSessionTags(sessionId, tags) {
|
|
2336
|
+
const normalized = normalizeSessionTags(tags);
|
|
2337
|
+
return mutateSessionMeta(sessionId, session => {
|
|
2338
|
+
session.tags = normalized.length > 0 ? normalized : undefined;
|
|
2339
|
+
session.updatedAt = Date.now();
|
|
2340
|
+
session.updatedAtIso = new Date(session.updatedAt).toISOString();
|
|
2341
|
+
});
|
|
2342
|
+
}
|
|
2343
|
+
/** Soft-delete: keeps every file but hides the session from default listings. */
|
|
2344
|
+
function archiveSession(sessionId) {
|
|
2345
|
+
return mutateSessionMeta(sessionId, session => {
|
|
2346
|
+
session.archivedAt = Date.now();
|
|
2347
|
+
session.updatedAt = session.archivedAt;
|
|
2348
|
+
session.updatedAtIso = new Date(session.updatedAt).toISOString();
|
|
2349
|
+
});
|
|
2350
|
+
}
|
|
2351
|
+
/** Bring an archived session back into the default listings. */
|
|
2352
|
+
function restoreSession(sessionId) {
|
|
2353
|
+
return mutateSessionMeta(sessionId, session => {
|
|
2354
|
+
delete session.archivedAt;
|
|
2355
|
+
session.updatedAt = Date.now();
|
|
2356
|
+
session.updatedAtIso = new Date(session.updatedAt).toISOString();
|
|
2357
|
+
});
|
|
2358
|
+
}
|
|
2295
2359
|
/**
|
|
2296
2360
|
* 删除会话
|
|
2297
2361
|
*/
|
|
@@ -17,15 +17,24 @@ const DEFAULT_CONFIG = {
|
|
|
17
17
|
simpleThresholdChars: 160,
|
|
18
18
|
simpleThresholdWords: 28,
|
|
19
19
|
strongKeywords: [
|
|
20
|
-
'plan',
|
|
21
|
-
'
|
|
22
|
-
'
|
|
23
|
-
'
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
'
|
|
27
|
-
'
|
|
20
|
+
'plan',
|
|
21
|
+
'design',
|
|
22
|
+
'implement',
|
|
23
|
+
'debug',
|
|
24
|
+
'refactor',
|
|
25
|
+
'architecture',
|
|
26
|
+
'optimize',
|
|
27
|
+
'security',
|
|
28
|
+
'performance',
|
|
29
|
+
'complex',
|
|
30
|
+
'analyze',
|
|
31
|
+
'investigate',
|
|
32
|
+
'troubleshoot',
|
|
33
|
+
'explain',
|
|
34
|
+
'review',
|
|
35
|
+
'audit',
|
|
28
36
|
],
|
|
37
|
+
simpleKeywords: ['fix', 'add', 'remove', 'update', 'rename', 'simple', 'quick', 'minor', 'small'],
|
|
29
38
|
};
|
|
30
39
|
exports.DEFAULT_ROUTING_CONFIG = DEFAULT_CONFIG;
|
|
31
40
|
// ============================================================================
|
|
@@ -112,9 +121,8 @@ function analyzeHistoryComplexity(messages) {
|
|
|
112
121
|
.filter(m => m.role === 'assistant')
|
|
113
122
|
.reduce((sum, m) => sum + (m.tool_calls?.length || 0), 0);
|
|
114
123
|
// 统计消息长度
|
|
115
|
-
const avgLength = messages
|
|
116
|
-
.
|
|
117
|
-
.reduce((sum, m) => sum + (m.content?.length || 0), 0) / messages.length;
|
|
124
|
+
const avgLength = messages.filter(m => m.content).reduce((sum, m) => sum + (m.content?.length || 0), 0) /
|
|
125
|
+
messages.length;
|
|
118
126
|
// 复杂度评分
|
|
119
127
|
const score = Math.min((toolCallCount / 10) * 0.5 + (avgLength / 500) * 0.5, 1);
|
|
120
128
|
return score;
|
|
@@ -123,22 +123,20 @@ function readPackageScripts(cwd) {
|
|
|
123
123
|
}
|
|
124
124
|
function hasUsefulScript(scripts, name) {
|
|
125
125
|
const script = scripts[name];
|
|
126
|
-
return typeof script === 'string'
|
|
127
|
-
&& script.trim().length > 0
|
|
128
|
-
&& !/no test specified/i.test(script);
|
|
126
|
+
return (typeof script === 'string' && script.trim().length > 0 && !/no test specified/i.test(script));
|
|
129
127
|
}
|
|
130
128
|
function normalizeCommand(command) {
|
|
131
129
|
return command.trim().replace(/\s+/g, ' ');
|
|
132
130
|
}
|
|
133
131
|
function isVerificationCommand(command) {
|
|
134
132
|
const normalized = normalizeCommand(command);
|
|
135
|
-
return /(^|\s)(npm|pnpm|yarn|bun)\s+(run\s+)?(build|test|lint|check)\b/i.test(normalized)
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
133
|
+
return (/(^|\s)(npm|pnpm|yarn|bun)\s+(run\s+)?(build|test|lint|check)\b/i.test(normalized) ||
|
|
134
|
+
/(^|\s)(npm|pnpm|yarn|bun)\s+run\s+prepublishOnly\b/i.test(normalized) ||
|
|
135
|
+
/(^|\s)(jest|vitest|mocha|ava|tsc|eslint)\b/i.test(normalized) ||
|
|
136
|
+
/(^|\s)(pytest|ruff|mypy|pyright|ty)\b/i.test(normalized) ||
|
|
137
|
+
/^uv\s+run\s+(pytest|ruff|mypy|pyright|ty)\b/i.test(normalized) ||
|
|
138
|
+
/^cargo\s+(test|clippy|check)\b/i.test(normalized) ||
|
|
139
|
+
/^go\s+test\b/i.test(normalized));
|
|
142
140
|
}
|
|
143
141
|
function collectVerificationCommandResult(params) {
|
|
144
142
|
if (params.toolName !== 'exec_command')
|
|
@@ -219,9 +217,9 @@ function summarizeVerificationState(profile, results) {
|
|
|
219
217
|
passedCommands,
|
|
220
218
|
failedCommands,
|
|
221
219
|
missingCommands,
|
|
222
|
-
claimAllowed: !profile.required
|
|
223
|
-
|
|
224
|
-
|
|
220
|
+
claimAllowed: !profile.required ||
|
|
221
|
+
expectedCommands.length === 0 ||
|
|
222
|
+
(missingCommands.length === 0 && failedCommands.length === 0),
|
|
225
223
|
skippedReason,
|
|
226
224
|
};
|
|
227
225
|
}
|
|
@@ -238,10 +236,7 @@ function nodeCommands(cwd) {
|
|
|
238
236
|
}
|
|
239
237
|
function pythonCommands(cwd) {
|
|
240
238
|
if ((0, fs_1.existsSync)((0, path_1.join)(cwd, 'pyproject.toml'))) {
|
|
241
|
-
return [
|
|
242
|
-
'uv run pytest',
|
|
243
|
-
'uv run ruff check .',
|
|
244
|
-
];
|
|
239
|
+
return ['uv run pytest', 'uv run ruff check .'];
|
|
245
240
|
}
|
|
246
241
|
if ((0, fs_1.existsSync)((0, path_1.join)(cwd, 'pytest.ini')) || (0, fs_1.existsSync)((0, path_1.join)(cwd, 'tests'))) {
|
|
247
242
|
return ['pytest'];
|
|
@@ -269,9 +264,9 @@ function selectVerificationProfile(cwd, changedFiles) {
|
|
|
269
264
|
reason: 'Documentation-only changes usually require review, not automated test commands.',
|
|
270
265
|
};
|
|
271
266
|
}
|
|
272
|
-
const nodeLike = (0, fs_1.existsSync)((0, path_1.join)(cwd, 'package.json'))
|
|
273
|
-
|
|
274
|
-
|
|
267
|
+
const nodeLike = (0, fs_1.existsSync)((0, path_1.join)(cwd, 'package.json')) &&
|
|
268
|
+
(hasAnyExtension(files, ['.ts', '.tsx', '.js', '.jsx', '.json']) ||
|
|
269
|
+
hasAnyPath(files, ['src', 'tests', 'bin']));
|
|
275
270
|
if (nodeLike) {
|
|
276
271
|
const commands = nodeCommands(cwd);
|
|
277
272
|
return {
|
|
@@ -284,8 +279,8 @@ function selectVerificationProfile(cwd, changedFiles) {
|
|
|
284
279
|
: 'Node/TypeScript project changes detected, but no build/test/lint scripts are configured.',
|
|
285
280
|
};
|
|
286
281
|
}
|
|
287
|
-
const pythonLike = ((0, fs_1.existsSync)((0, path_1.join)(cwd, 'pyproject.toml')) || (0, fs_1.existsSync)((0, path_1.join)(cwd, 'pytest.ini')))
|
|
288
|
-
|
|
282
|
+
const pythonLike = ((0, fs_1.existsSync)((0, path_1.join)(cwd, 'pyproject.toml')) || (0, fs_1.existsSync)((0, path_1.join)(cwd, 'pytest.ini'))) &&
|
|
283
|
+
hasAnyExtension(files, ['.py', '.toml']);
|
|
289
284
|
if (pythonLike) {
|
|
290
285
|
const commands = pythonCommands(cwd);
|
|
291
286
|
return {
|
|
@@ -17,7 +17,8 @@ const PROVIDER_PROFILES = [
|
|
|
17
17
|
apiKeyEnvVars: [ORION_WEBSEARCH_API_KEY, 'DASHSCOPE_API_KEY'],
|
|
18
18
|
matches(config) {
|
|
19
19
|
const baseUrl = (config.apiBaseUrl || '').toLowerCase();
|
|
20
|
-
return baseUrl.includes('dashscope.aliyuncs.com') ||
|
|
20
|
+
return (baseUrl.includes('dashscope.aliyuncs.com') ||
|
|
21
|
+
baseUrl.includes('dashscope-intl.aliyuncs.com'));
|
|
21
22
|
},
|
|
22
23
|
note: 'Bailian WebSearch MCP. Official docs currently list the dashscope endpoint for Coding Plan tools.',
|
|
23
24
|
},
|
|
@@ -30,7 +31,8 @@ const PROVIDER_PROFILES = [
|
|
|
30
31
|
matches(config) {
|
|
31
32
|
const baseUrl = (config.apiBaseUrl || '').toLowerCase();
|
|
32
33
|
const model = (config.model || '').toLowerCase();
|
|
33
|
-
return baseUrl.includes('bigmodel.cn') ||
|
|
34
|
+
return (baseUrl.includes('bigmodel.cn') ||
|
|
35
|
+
(model.startsWith('glm') && !baseUrl.includes('dashscope')));
|
|
34
36
|
},
|
|
35
37
|
note: 'ZhipuAI GLM WebSearch Prime MCP.',
|
|
36
38
|
},
|
|
@@ -55,7 +57,7 @@ function findProfile(provider) {
|
|
|
55
57
|
const normalized = normalizeProvider(provider);
|
|
56
58
|
if (!normalized || normalized === 'auto')
|
|
57
59
|
return undefined;
|
|
58
|
-
return PROVIDER_PROFILES.find(profile =>
|
|
60
|
+
return PROVIDER_PROFILES.find(profile => profile.id === normalized || profile.aliases.includes(normalized));
|
|
59
61
|
}
|
|
60
62
|
function inferProfile(config) {
|
|
61
63
|
return PROVIDER_PROFILES.find(profile => profile.matches(config)) || PROVIDER_PROFILES[0];
|
|
@@ -86,15 +88,20 @@ function resolveWebSearchMcpConfig(config) {
|
|
|
86
88
|
const envApiKeyQueryParam = process.env[(0, environment_1.webSearchEnv)('API_KEY_QUERY_PARAM')];
|
|
87
89
|
const providerApiKey = firstEnvValue(profile.apiKeyEnvVars);
|
|
88
90
|
const configuredApiKey = config.apiKey || process.env[environment_1.ENV.API_KEY];
|
|
89
|
-
const authType =
|
|
90
|
-
|
|
91
|
+
const authType = explicit.authType ||
|
|
92
|
+
(envAuthType === 'bearer' ||
|
|
93
|
+
envAuthType === 'header' ||
|
|
94
|
+
envAuthType === 'query' ||
|
|
95
|
+
envAuthType === 'none'
|
|
91
96
|
? envAuthType
|
|
92
|
-
: undefined)
|
|
93
|
-
|
|
97
|
+
: undefined) ||
|
|
98
|
+
profile.authType;
|
|
94
99
|
return {
|
|
95
100
|
provider: profile.id,
|
|
96
101
|
endpoint: explicit.endpoint || envEndpoint || profile.endpoint,
|
|
97
|
-
apiKey: explicit.apiKey ||
|
|
102
|
+
apiKey: explicit.apiKey ||
|
|
103
|
+
providerApiKey ||
|
|
104
|
+
(hasExplicitCredential(explicit) ? undefined : configuredApiKey),
|
|
98
105
|
toolName: explicit.toolName || envToolName || profile.toolName,
|
|
99
106
|
timeoutMs: explicit.timeoutMs,
|
|
100
107
|
authType,
|
|
@@ -122,6 +129,11 @@ function getWebSearchMcpErrorSuggestion(config) {
|
|
|
122
129
|
].join(' ');
|
|
123
130
|
}
|
|
124
131
|
function listWebSearchProviderProfiles() {
|
|
125
|
-
return PROVIDER_PROFILES.map(({ id, endpoint, aliases, toolName }) => ({
|
|
132
|
+
return PROVIDER_PROFILES.map(({ id, endpoint, aliases, toolName }) => ({
|
|
133
|
+
id,
|
|
134
|
+
endpoint,
|
|
135
|
+
aliases,
|
|
136
|
+
toolName,
|
|
137
|
+
}));
|
|
126
138
|
}
|
|
127
139
|
//# sourceMappingURL=web-search-provider.js.map
|