@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.
Files changed (95) hide show
  1. package/CHANGELOG.md +157 -0
  2. package/README.md +59 -5
  3. package/README.zh-CN.md +6 -3
  4. package/dist/cli.js +58 -32
  5. package/dist/commands/context-tool-command-handlers.js +1 -5
  6. package/dist/commands/registry.js +1 -4
  7. package/dist/harness/intent.js +69 -16
  8. package/dist/harness/turn-summary.js +3 -1
  9. package/dist/memory/embeddings.js +2 -3
  10. package/dist/memory/prompts.js +1 -1
  11. package/dist/memory/relevant-finder.js +125 -15
  12. package/dist/memory/vector-store.js +13 -8
  13. package/dist/migration/migrate.js +8 -12
  14. package/dist/runtime/composer/history.js +1 -3
  15. package/dist/runtime/composer/layout.js +7 -4
  16. package/dist/runtime/legacy-thread-materializer.d.ts +3 -1
  17. package/dist/runtime/legacy-thread-materializer.js +15 -3
  18. package/dist/runtime/product-bootstrap.d.ts +12 -0
  19. package/dist/runtime/product-bootstrap.js +37 -22
  20. package/dist/runtime/rich-text/ansi-parser.js +12 -2
  21. package/dist/runtime/rich-text/layout.js +15 -19
  22. package/dist/runtime/subagents/budget.js +4 -1
  23. package/dist/runtime/subagents/policy.js +11 -4
  24. package/dist/runtime/subagents/provider-gate.js +6 -4
  25. package/dist/runtime/subagents/research-quality.js +3 -1
  26. package/dist/runtime/subagents/research-renderer.js +9 -2
  27. package/dist/runtime/subagents/result-parser.js +18 -7
  28. package/dist/runtime/thread-event-store.d.ts +5 -3
  29. package/dist/runtime/thread-event-store.js +29 -8
  30. package/dist/runtime/thread-projection.d.ts +17 -0
  31. package/dist/runtime/thread-projection.js +42 -1
  32. package/dist/runtime/tool-output-presentation.js +7 -7
  33. package/dist/runtime/turn-controller.js +1 -2
  34. package/dist/services/auth/auth.js +1 -4
  35. package/dist/services/auth/aws.js +24 -14
  36. package/dist/services/auto-fix/autoFixRunner.js +1 -1
  37. package/dist/services/auto-fix/index.d.ts +1 -1
  38. package/dist/services/diagnostic-tracking/diagnosticTracking.js +4 -2
  39. package/dist/services/diagnostic-tracking/index.d.ts +1 -1
  40. package/dist/services/effort.js +1 -9
  41. package/dist/services/file-glob.js +3 -4
  42. package/dist/services/mcp/transports.js +4 -4
  43. package/dist/services/model-catalog.js +179 -30
  44. package/dist/services/model-context.js +1 -1
  45. package/dist/services/provider-resilience/stream-recovery.js +1 -3
  46. package/dist/services/redaction.js +8 -0
  47. package/dist/services/session-storage.d.ts +28 -3
  48. package/dist/services/session-storage.js +70 -6
  49. package/dist/services/smart-routing.js +19 -11
  50. package/dist/services/verification-profile.js +17 -22
  51. package/dist/services/web-search-provider.js +21 -9
  52. package/dist/services/workspace-diff.js +10 -4
  53. package/dist/skills/builtin/code-review/SKILL.md +1 -1
  54. package/dist/skills/builtin/security-check/SKILL.md +1 -1
  55. package/dist/skills/builtin/test-gen/SKILL.md +1 -1
  56. package/dist/terminal-ui/editor.js +6 -2
  57. package/dist/terminal-ui/output-queue.js +9 -3
  58. package/dist/tools/lsp.js +12 -6
  59. package/dist/tui-core/frame.js +9 -7
  60. package/dist/tui-ui/transcript-cache.js +6 -6
  61. package/dist/tui-ui/transcript-inspector-surface.js +4 -1
  62. package/dist/tui-ui/transcript-inspector.js +3 -8
  63. package/dist/ui/box.js +14 -7
  64. package/dist/ui/markdown.js +4 -2
  65. package/dist/ui/shared/input-frame.js +12 -8
  66. package/dist/ui/stream-markdown.js +1 -1
  67. package/dist/ui/tool-preview.js +11 -3
  68. package/dist/ui/user-input.js +16 -10
  69. package/dist/web/cli-options.d.ts +13 -0
  70. package/dist/web/cli-options.js +47 -0
  71. package/dist/web/host-daemon.d.ts +61 -0
  72. package/dist/web/host-daemon.js +193 -0
  73. package/dist/web/launch.d.ts +3 -0
  74. package/dist/web/launch.js +24 -0
  75. package/dist/web/protocol.d.ts +2 -0
  76. package/dist/web/protocol.js +1 -0
  77. package/dist/web/review-service.js +41 -13
  78. package/dist/web/server.js +69 -0
  79. package/dist/web/session-runtime-registry.d.ts +14 -0
  80. package/dist/web/session-runtime-registry.js +23 -0
  81. package/dist/web/workbench-controller.d.ts +55 -0
  82. package/dist/web/workbench-controller.js +224 -14
  83. package/dist/web-client/assets/{DiffViewer-D6mG729y.js → DiffViewer-MMhvMif-.js} +1 -1
  84. package/dist/web-client/assets/{FilesPanel-CCDoAZ1J.js → FilesPanel-4litEN1k.js} +1 -1
  85. package/dist/web-client/assets/{GitPanel-DtNgiH7A.js → GitPanel-BVwlDRVo.js} +1 -1
  86. package/dist/web-client/assets/ReviewPanel-ChA0Zd2g.js +1 -0
  87. package/dist/web-client/assets/{TerminalPanel-CNxMaBLp.js → TerminalPanel-D8C1uybv.js} +1 -1
  88. package/dist/web-client/assets/index-DQfpqPTD.css +1 -0
  89. package/dist/web-client/assets/index-Dv_uE9dk.js +17 -0
  90. package/dist/web-client/index.html +2 -2
  91. package/npm-shrinkwrap.json +356 -120
  92. package/package.json +3 -1
  93. package/dist/web-client/assets/ReviewPanel-CKEBSt6P.js +0 -1
  94. package/dist/web-client/assets/index-BBvNg3By.css +0 -1
  95. 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
- { name: 'claude-opus-4-8', alias: 'opus', provider: 'Anthropic', contextWindow: 200000, maxOutputTokens: 32000 },
11
- { name: 'claude-sonnet-4-6', alias: 'sonnet', provider: 'Anthropic', contextWindow: 200000, maxOutputTokens: 16000 },
12
- { name: 'claude-haiku-4-5-20251001', alias: 'haiku', provider: 'Anthropic', contextWindow: 200000, maxOutputTokens: 8192 },
13
- { name: 'gpt-4o', alias: 'gpt4o', provider: 'OpenAI', contextWindow: 128000, maxOutputTokens: 16384 },
14
- { name: 'gpt-4o-mini', alias: 'gpt4omin', provider: 'OpenAI', contextWindow: 128000, maxOutputTokens: 16384 },
15
- { name: 'gpt-3.5-turbo', alias: 'gpt35', provider: 'OpenAI', contextWindow: 16385, maxOutputTokens: 4096 },
16
- { name: 'glm-5', alias: 'glm', provider: 'Bailian (Zhipu)', contextWindow: 202752, maxOutputTokens: 8192 },
17
- { name: 'glm-4.7', alias: 'glm47', provider: 'Bailian (Zhipu)', contextWindow: 131072, maxOutputTokens: 8192 },
18
- { name: 'glm-5.2', alias: 'glm52', provider: 'Huoshan (Volcengine)', contextWindow: 1024000, maxOutputTokens: 128000 },
19
- { name: 'qwen3.7-plus', alias: 'qwen', provider: 'Bailian (Alibaba)', contextWindow: 131072, maxOutputTokens: 8192 },
20
- { name: 'qwen3.6-plus', alias: 'qwen36', provider: 'Bailian (Alibaba)', contextWindow: 131072, maxOutputTokens: 8192 },
21
- { name: 'qwen3.5-plus', alias: 'qwen35', provider: 'Bailian (Alibaba)', contextWindow: 131072, maxOutputTokens: 8192 },
22
- { name: 'qwen3-max-2026-01-23', alias: 'qwenmax', provider: 'Bailian (Alibaba)', contextWindow: 131072, maxOutputTokens: 8192 },
23
- { name: 'qwen3-coder-plus', alias: 'coder', provider: 'Bailian (Alibaba)', contextWindow: 131072, maxOutputTokens: 8192 },
24
- { name: 'qwen3-coder-next', alias: 'codernext', provider: 'Bailian (Alibaba)', contextWindow: 131072, maxOutputTokens: 8192 },
25
- { name: 'kimi-k2.5', alias: 'kimi', provider: 'Bailian (Moonshot)', contextWindow: 131072, maxOutputTokens: 8192 },
26
- { name: 'kimi-k2.7-code', alias: 'kimicode', provider: 'Huoshan (Volcengine)', contextWindow: 256000, maxOutputTokens: 32768 },
27
- { name: 'MiniMax-M2.5', alias: 'minimax', provider: 'Bailian (MiniMax)', contextWindow: 131072, maxOutputTokens: 8192 },
28
- { name: 'ark-code-latest', alias: 'ark', provider: 'Huoshan (Volcengine)', contextWindow: 1024000, maxOutputTokens: 128000 },
29
- { name: 'deepseek-v4-pro', alias: 'dsv4pro', provider: 'Huoshan (Volcengine)', contextWindow: 1000000, maxOutputTokens: 384000 },
30
- { name: 'xopdeepseekv4pro', alias: 'xdsv4pro', provider: 'XF MAAS (xf-yun)', contextWindow: 1000000, maxOutputTokens: 16384 },
31
- { name: 'xopglm51', alias: 'xglm51', provider: 'XF MAAS (xf-yun)', contextWindow: 204800, maxOutputTokens: 16384 },
32
- { name: 'astron-code-latest', alias: 'astron', provider: 'XF MAAS (xf-yun)', contextWindow: 92160, maxOutputTokens: 32768 },
33
- { name: 'deepseek-chat', alias: 'dschat', provider: 'DeepSeek', contextWindow: 64000, maxOutputTokens: 8192 },
34
- { name: 'deepseek-coder', alias: 'dscoder', provider: 'DeepSeek', contextWindow: 64000, maxOutputTokens: 8192 },
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 || normalizeCatalogKey(entry.alias) === 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', 'design', 'implement', 'debug', 'refactor',
21
- 'architecture', 'optimize', 'security', 'performance',
22
- 'complex', 'analyze', 'investigate', 'troubleshoot',
23
- 'explain', 'review', 'audit',
24
- ],
25
- simpleKeywords: [
26
- 'fix', 'add', 'remove', 'update', 'rename',
27
- 'simple', 'quick', 'minor', 'small',
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
- .filter(m => m.content)
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
- || /(^|\s)(npm|pnpm|yarn|bun)\s+run\s+prepublishOnly\b/i.test(normalized)
137
- || /(^|\s)(jest|vitest|mocha|ava|tsc|eslint)\b/i.test(normalized)
138
- || /(^|\s)(pytest|ruff|mypy|pyright|ty)\b/i.test(normalized)
139
- || /^uv\s+run\s+(pytest|ruff|mypy|pyright|ty)\b/i.test(normalized)
140
- || /^cargo\s+(test|clippy|check)\b/i.test(normalized)
141
- || /^go\s+test\b/i.test(normalized);
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
- || expectedCommands.length === 0
224
- || (missingCommands.length === 0 && failedCommands.length === 0),
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
- && (hasAnyExtension(files, ['.ts', '.tsx', '.js', '.jsx', '.json'])
274
- || hasAnyPath(files, ['src', 'tests', 'bin']));
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
- && hasAnyExtension(files, ['.py', '.toml']);
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') || baseUrl.includes('dashscope-intl.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') || (model.startsWith('glm') && !baseUrl.includes('dashscope'));
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 => (profile.id === normalized || profile.aliases.includes(normalized)));
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 = (explicit.authType
90
- || (envAuthType === 'bearer' || envAuthType === 'header' || envAuthType === 'query' || envAuthType === 'none'
91
+ const authType = explicit.authType ||
92
+ (envAuthType === 'bearer' ||
93
+ envAuthType === 'header' ||
94
+ envAuthType === 'query' ||
95
+ envAuthType === 'none'
91
96
  ? envAuthType
92
- : undefined)
93
- || profile.authType);
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 || providerApiKey || (hasExplicitCredential(explicit) ? undefined : configuredApiKey),
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 }) => ({ 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