cc-viewer 1.7.23 → 1.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -0
- package/cli.js +92 -11
- package/concepts/ar/GlobalSettings.md +2 -2
- package/concepts/ar/ToolsFirst.md +1 -1
- package/concepts/da/GlobalSettings.md +2 -2
- package/concepts/da/ToolsFirst.md +1 -1
- package/concepts/de/GlobalSettings.md +2 -2
- package/concepts/de/ToolsFirst.md +1 -1
- package/concepts/en/GlobalSettings.md +2 -2
- package/concepts/en/ToolsFirst.md +1 -1
- package/concepts/es/GlobalSettings.md +2 -2
- package/concepts/es/ToolsFirst.md +1 -1
- package/concepts/fr/GlobalSettings.md +2 -2
- package/concepts/fr/ToolsFirst.md +1 -1
- package/concepts/it/GlobalSettings.md +2 -2
- package/concepts/it/ToolsFirst.md +1 -1
- package/concepts/ja/GlobalSettings.md +2 -2
- package/concepts/ja/ToolsFirst.md +1 -1
- package/concepts/ko/GlobalSettings.md +2 -2
- package/concepts/ko/ToolsFirst.md +1 -1
- package/concepts/no/GlobalSettings.md +2 -2
- package/concepts/no/ToolsFirst.md +1 -1
- package/concepts/pl/GlobalSettings.md +2 -2
- package/concepts/pl/ToolsFirst.md +1 -1
- package/concepts/pt-BR/GlobalSettings.md +2 -2
- package/concepts/pt-BR/ToolsFirst.md +1 -1
- package/concepts/ru/GlobalSettings.md +2 -2
- package/concepts/ru/ToolsFirst.md +1 -1
- package/concepts/th/GlobalSettings.md +2 -2
- package/concepts/th/ToolsFirst.md +1 -1
- package/concepts/tr/GlobalSettings.md +2 -2
- package/concepts/tr/ToolsFirst.md +1 -1
- package/concepts/uk/GlobalSettings.md +2 -2
- package/concepts/uk/ToolsFirst.md +1 -1
- package/concepts/zh/GlobalSettings.md +2 -2
- package/concepts/zh/ToolsFirst.md +1 -1
- package/concepts/zh-TW/GlobalSettings.md +2 -2
- package/concepts/zh-TW/ToolsFirst.md +1 -1
- package/dist/assets/App-CqQJDjfT.js +2 -0
- package/dist/assets/App-ssYfrjwF.css +1 -0
- package/dist/assets/{MdxEditorPanel-e5DlfcqJ.js → MdxEditorPanel-DXwb5tSD.js} +1 -1
- package/dist/assets/{Mobile-B8xwCLgr.js → Mobile-DOjKURO3.js} +1 -1
- package/dist/assets/{ProxyStatsModal-_w677xPM.js → ProxyStatsModal-BEnxiRXF.js} +1 -1
- package/dist/assets/index-CH_N7vvX.js +2 -0
- package/dist/assets/seqResourceLoaders-BJhO6zhW.js +2 -0
- package/dist/assets/seqResourceLoaders-DI0G5nu1.css +41 -0
- package/dist/index.html +1 -1
- package/findcc.js +17 -8
- package/node_modules/@ccv/core/package.json +13 -0
- package/{server/lib → node_modules/@ccv/core/src}/approval-modal-prefs.js +1 -1
- package/node_modules/@ccv/core/src/clearCheckpoint.js +7 -0
- package/{src/utils → node_modules/@ccv/core/src}/contentFilter.js +207 -141
- package/{server/lib → node_modules/@ccv/core/src}/context-rules.js +2 -2
- package/{server/lib → node_modules/@ccv/core/src}/delta-reconstructor.js +60 -4
- package/{server/lib → node_modules/@ccv/core/src}/error-report.js +5 -4
- package/{server/lib → node_modules/@ccv/core/src}/session-boundary.js +3 -3
- package/{src/utils → node_modules/@ccv/core/src}/teammateDetector.js +9 -0
- package/{server/lib → node_modules/@ccv/core/src}/tools-xml-formatter.js +3 -3
- package/{server/lib → node_modules/@ccv/core/src}/v2-transcript-normalizer.js +1 -1
- package/{server/lib → node_modules/@ccv/core/src}/voice-pack-events.js +2 -2
- package/package.json +11 -97
- package/server/_paths.js +28 -7
- package/server/i18n.js +60 -0
- package/server/interceptor.js +36 -11
- package/server/lib/adapters/dingtalk-adapter.js +2 -2
- package/server/lib/adapters/discord-adapter.js +2 -2
- package/server/lib/adapters/feishu-adapter.js +2 -2
- package/server/lib/adapters/wecom-adapter.js +2 -2
- package/server/lib/approval-policy.js +29 -0
- package/server/lib/{ask-store.js → ask/ask-store.js} +3 -3
- package/server/lib/{perm-bridge.js → ask/perm-bridge.js} +5 -5
- package/server/lib/builtin-model-prompts.js +198 -0
- package/server/lib/chat-queue.js +341 -0
- package/server/lib/cli-inject.js +1 -1
- package/server/lib/context-watcher.js +3 -3
- package/server/lib/create_system_prompt.js +0 -9
- package/server/lib/enrich-plan-input.js +1 -1
- package/server/lib/ensure-hooks.js +2 -2
- package/server/lib/file-access-policy.js +6 -1
- package/server/lib/file-api.js +17 -1
- package/server/lib/{dingtalk-bridge.js → im/dingtalk-bridge.js} +1 -1
- package/server/lib/{im-append-system.js → im/im-append-system.js} +5 -13
- package/server/lib/{im-bridge-core.js → im/im-bridge-core.js} +12 -6
- package/server/lib/{im-config.js → im/im-config.js} +1 -1
- package/server/lib/im/im-deny.js +4 -0
- package/server/lib/{im-lang.js → im/im-lang.js} +1 -1
- package/server/lib/{im-lock.js → im/im-lock.js} +2 -2
- package/server/lib/{im-process-manager.js → im/im-process-manager.js} +1 -1
- package/server/lib/{im-senders.js → im/im-senders.js} +1 -1
- package/server/lib/{im-skills.js → im/im-skills.js} +2 -2
- package/server/lib/interceptor-core.js +8 -5
- package/server/lib/kv-cache-analyzer.js +6 -5
- package/server/lib/launch-config.js +329 -0
- package/server/lib/log-file-utils.js +21 -0
- package/server/lib/log-management.js +6 -17
- package/server/lib/log-stream.js +1 -1
- package/server/lib/log-watcher.js +1 -1
- package/server/lib/model-system-prompts.js +18 -2
- package/server/lib/prefs-store.js +2 -2
- package/server/lib/project-prefs.js +6 -6
- package/server/lib/project-state.js +15 -0
- package/server/lib/{proxy-retry.js → proxy/proxy-retry.js} +2 -2
- package/server/lib/{proxy-stats.js → proxy/proxy-stats.js} +3 -3
- package/server/lib/sdk-adapter.js +6 -74
- package/server/lib/sdk-manager.js +383 -278
- package/server/lib/skills-api.js +1 -1
- package/server/lib/spawn-model-resolver.js +21 -6
- package/server/lib/stats-worker.js +2 -2
- package/server/lib/system-prompt-files.js +53 -15
- package/server/lib/system-prompt-render.js +23 -7
- package/server/lib/system-prompt-snapshots.js +452 -0
- package/server/lib/updater.js +63 -3
- package/server/lib/user-prompt-extract.js +5 -5
- package/server/lib/v2/adapter.js +3 -3
- package/server/lib/v2/conversation-store.js +1 -1
- package/server/lib/v2/convert.js +3 -3
- package/server/lib/v2/jsonl-read.js +1 -1
- package/server/lib/v2/live-feed.js +3 -3
- package/server/lib/v2/meta-rows.js +3 -3
- package/server/lib/v2/replay.js +1 -1
- package/server/lib/v2/session-list.js +1 -1
- package/server/lib/v2/session-owner.js +1 -1
- package/server/lib/v2/v2-writer.js +26 -1
- package/server/lib/v2/verify.js +1 -1
- package/server/lib/voice-pack-manager.js +4 -5
- package/server/lib/wire-compress.js +1 -1
- package/server/proxy.js +5 -5
- package/server/pty-manager.js +285 -184
- package/server/routes/ask-perm.js +1 -1
- package/server/routes/dingtalk.js +3 -3
- package/server/routes/events.js +2 -2
- package/server/routes/expert.js +74 -13
- package/server/routes/im.js +5 -5
- package/server/routes/preferences.js +3 -3
- package/server/routes/workspaces.js +1 -1
- package/server/server.js +207 -58
- package/server/system-prompt-templates/systemPromptModel.md +0 -8
- package/server/system-prompt-templates/systemPromptVariables.ar.md +0 -7
- package/server/system-prompt-templates/systemPromptVariables.da.md +0 -7
- package/server/system-prompt-templates/systemPromptVariables.de.md +0 -7
- package/server/system-prompt-templates/systemPromptVariables.es.md +0 -7
- package/server/system-prompt-templates/systemPromptVariables.fr.md +0 -7
- package/server/system-prompt-templates/systemPromptVariables.it.md +0 -7
- package/server/system-prompt-templates/systemPromptVariables.ja.md +0 -7
- package/server/system-prompt-templates/systemPromptVariables.ko.md +0 -7
- package/server/system-prompt-templates/systemPromptVariables.md +0 -7
- package/server/system-prompt-templates/systemPromptVariables.no.md +0 -7
- package/server/system-prompt-templates/systemPromptVariables.pl.md +0 -7
- package/server/system-prompt-templates/systemPromptVariables.pt-BR.md +0 -7
- package/server/system-prompt-templates/systemPromptVariables.ru.md +0 -7
- package/server/system-prompt-templates/systemPromptVariables.th.md +0 -7
- package/server/system-prompt-templates/systemPromptVariables.tr.md +0 -7
- package/server/system-prompt-templates/systemPromptVariables.uk.md +0 -7
- package/server/system-prompt-templates/systemPromptVariables.zh-TW.md +0 -7
- package/server/system-prompt-templates/systemPromptVariables.zh.md +0 -7
- package/ultraAgents/README.md +3 -0
- package/ultraAgents/test-analysis-expert.json +45 -0
- package/dist/assets/App-BWajJyJh.css +0 -1
- package/dist/assets/App-CusqoEAB.js +0 -2
- package/dist/assets/index-D6FmFsIz.js +0 -2
- package/dist/assets/seqResourceLoaders-3K77Znll.js +0 -2
- package/dist/assets/seqResourceLoaders-BgD_Rwvc.css +0 -41
- package/src/utils/apiUrl.js +0 -26
- package/src/utils/askFallback.js +0 -21
- package/src/utils/askOptionDesc.js +0 -55
- package/src/utils/askPortalMatcher.js +0 -54
- package/src/utils/autoApproveOptions.js +0 -27
- package/src/utils/avatarAnimationPostPass.js +0 -49
- package/src/utils/builtinPresets.js +0 -18
- package/src/utils/clearCheckpoint.js +0 -7
- package/src/utils/commandValidator.js +0 -45
- package/src/utils/contextRaw.js +0 -18
- package/src/utils/contextSidebarNavigation.js +0 -16
- package/src/utils/contextTurns.js +0 -117
- package/src/utils/displayScaleHelper.js +0 -47
- package/src/utils/effectiveModel.js +0 -17
- package/src/utils/entry-slim.js +0 -563
- package/src/utils/entryCache.js +0 -144
- package/src/utils/errorReport.js +0 -6
- package/src/utils/fileExpandedPathsStorage.js +0 -70
- package/src/utils/fileIcons.jsx +0 -36
- package/src/utils/fileOpen.js +0 -37
- package/src/utils/formatters.js +0 -48
- package/src/utils/gitApi.js +0 -50
- package/src/utils/gitTreeBuilder.js +0 -19
- package/src/utils/helpers.js +0 -854
- package/src/utils/identityHeal.js +0 -108
- package/src/utils/imConnState.js +0 -59
- package/src/utils/imOrigin.js +0 -24
- package/src/utils/imTr.js +0 -7
- package/src/utils/imageCompress.js +0 -83
- package/src/utils/imageDownscale.js +0 -28
- package/src/utils/imageResize.js +0 -112
- package/src/utils/ingestPipeline.js +0 -47
- package/src/utils/isProxyMode.js +0 -11
- package/src/utils/lazyWithReload.js +0 -53
- package/src/utils/markdown.js +0 -30
- package/src/utils/markdownIncremental.js +0 -39
- package/src/utils/markdownProfiler.js +0 -113
- package/src/utils/mdExtensionDetect.js +0 -64
- package/src/utils/memoryLinkParser.js +0 -44
- package/src/utils/modalMask.js +0 -15
- package/src/utils/modelSuggestions.js +0 -48
- package/src/utils/monotime.js +0 -6
- package/src/utils/pinnedMenu.js +0 -55
- package/src/utils/presetShortcuts.js +0 -14
- package/src/utils/projectAlias.js +0 -135
- package/src/utils/promptClassifier.js +0 -112
- package/src/utils/promptDetect.js +0 -196
- package/src/utils/promptNav.js +0 -60
- package/src/utils/ptyChunkBuilder.js +0 -251
- package/src/utils/quickMenuHoverIntent.js +0 -35
- package/src/utils/rateLimitParser.js +0 -119
- package/src/utils/readResultPool.js +0 -106
- package/src/utils/refreshCachedItemProp.js +0 -30
- package/src/utils/resizeCalc.js +0 -21
- package/src/utils/resolveLocalized.js +0 -17
- package/src/utils/searchApi.js +0 -47
- package/src/utils/searchReplace.js +0 -51
- package/src/utils/seqResourceLoaders.js +0 -79
- package/src/utils/sessionManager.js +0 -482
- package/src/utils/sessionMerge.js +0 -239
- package/src/utils/skillModalController.js +0 -111
- package/src/utils/skillsParser.js +0 -116
- package/src/utils/slashCommandLabels.js +0 -80
- package/src/utils/splitDragCalc.js +0 -73
- package/src/utils/stickyBottomController.js +0 -643
- package/src/utils/svgSanitize.js +0 -48
- package/src/utils/systemTags.js +0 -47
- package/src/utils/tClaude.js +0 -20
- package/src/utils/teamModalBuilder.js +0 -351
- package/src/utils/teamSessionParser.js +0 -190
- package/src/utils/teammateAvatars.js +0 -194
- package/src/utils/termDiag.js +0 -114
- package/src/utils/terminalClipboard.js +0 -117
- package/src/utils/terminalWriteQueue.js +0 -398
- package/src/utils/thinkingMerge.js +0 -49
- package/src/utils/toolCatalog.js +0 -30
- package/src/utils/toolResultBuilder.js +0 -411
- package/src/utils/toolResultClassifier.js +0 -16
- package/src/utils/toolResultCore.js +0 -194
- package/src/utils/toolsDiff.js +0 -44
- package/src/utils/toolsXmlFormatter.js +0 -3
- package/src/utils/ultraplanController.js +0 -109
- package/src/utils/ultraplanExperts.js +0 -86
- package/src/utils/ultraplanTemplates.js +0 -154
- package/src/utils/userImageRefs.js +0 -49
- package/src/utils/v3Assembler.js +0 -125
- package/src/utils/v3Rows.js +0 -49
- package/src/utils/voicePackPlayer.js +0 -233
- package/src/utils/webSearchGrouping.js +0 -111
- package/src/utils/workflowFormat.js +0 -52
- package/src/utils/workflowRuns.js +0 -118
- package/src/utils/workflowStore.js +0 -94
- /package/{src/utils → node_modules/@ccv/core/src}/requestType.js +0 -0
- /package/server/lib/{ask-bridge.js → ask/ask-bridge.js} +0 -0
- /package/server/lib/{ask-constants.js → ask/ask-constants.js} +0 -0
- /package/server/lib/{ask-reaper.js → ask/ask-reaper.js} +0 -0
- /package/server/lib/{dingtalk-config.js → im/dingtalk-config.js} +0 -0
- /package/server/lib/{im-log-watcher.js → im/im-log-watcher.js} +0 -0
- /package/server/lib/{proxy-env.js → proxy/proxy-env.js} +0 -0
- /package/server/lib/{proxy-errors.js → proxy/proxy-errors.js} +0 -0
package/server/lib/cli-inject.js
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
// * buildInjectBlockRegex 用 `\r?\n` 匹配,可同时识别两种形式的历史 marker;
|
|
17
17
|
// * 改成参数化 EOL 会破坏 LEGACY 形式的回归匹配(老 marker 是 `\n` 写入的)。
|
|
18
18
|
// - 因此注入后 CRLF 文件**会含混合 EOL**(块内 LF + 块外 CRLF),这是已知的、
|
|
19
|
-
// 被 test/cli-inject.test.js 'CRLF 文件注入后原 CRLF 部分被保留' 用例固化的行为。
|
|
19
|
+
// 被 packages/app/test/cli-inject.test.js 'CRLF 文件注入后原 CRLF 部分被保留' 用例固化的行为。
|
|
20
20
|
|
|
21
21
|
import { readFileSync, writeFileSync, existsSync } from 'node:fs';
|
|
22
22
|
|
|
@@ -2,7 +2,7 @@ import { readFileSync, existsSync, realpathSync } from 'node:fs';
|
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { homedir } from 'node:os';
|
|
4
4
|
import { getClaudeConfigDir } from '../../findcc.js';
|
|
5
|
-
import { getModelMaxTokens, adaptContextWindow, sumUsageInputTokens, sumUsageContextTokens, getCalibrationModel } from '
|
|
5
|
+
import { getModelMaxTokens, adaptContextWindow, sumUsageInputTokens, sumUsageContextTokens, getCalibrationModel } from '@ccv/core/context-rules';
|
|
6
6
|
|
|
7
7
|
export const CONTEXT_WINDOW_FILE = join(getClaudeConfigDir(), 'context-window.json');
|
|
8
8
|
export const CLAUDE_SETTINGS_FILE = join(getClaudeConfigDir(), 'settings.json');
|
|
@@ -27,7 +27,7 @@ export function readModelContextSize() {
|
|
|
27
27
|
const modelId = data?.model?.id || null;
|
|
28
28
|
let contextSize = 200000;
|
|
29
29
|
if (modelId) {
|
|
30
|
-
// [Nk]/[Nm] 后缀与家族档位统一走共享规则表(
|
|
30
|
+
// [Nk]/[Nm] 后缀与家族档位统一走共享规则表(@ccv/core/context-rules)
|
|
31
31
|
contextSize = getModelMaxTokens(modelId);
|
|
32
32
|
// Cache the base name → size mapping
|
|
33
33
|
const base = modelId.toLowerCase().replace(/^claude-/i, '').replace(/\[.*\]/, '').trim();
|
|
@@ -70,7 +70,7 @@ export function getContextSizeForModel(modelOrEntry) {
|
|
|
70
70
|
if (_startupModelBase && base === _startupModelBase) {
|
|
71
71
|
return _startupContextSize;
|
|
72
72
|
}
|
|
73
|
-
// 完整档位表见
|
|
73
|
+
// 完整档位表见 @ccv/core/context-rules(与前端同源;含 haiku/旧 opus/3-opus 200K、
|
|
74
74
|
// deepseek-v4 1M、kimi/moonshot 256K、gpt/deepseek 等三方档位,默认 200K)
|
|
75
75
|
return getModelMaxTokens(apiModelName);
|
|
76
76
|
}
|
|
@@ -181,9 +181,6 @@ export function createSystemPromptVariables(overrides = {}, opts = {}) {
|
|
|
181
181
|
userName: isGitRepository
|
|
182
182
|
? commandOutput('git', ['config', 'user.name'], cwd)
|
|
183
183
|
: '',
|
|
184
|
-
status: isGitRepository
|
|
185
|
-
? commandOutput('git', ['status', '--short'], cwd)
|
|
186
|
-
: '',
|
|
187
184
|
recentCommits: isGitRepository
|
|
188
185
|
? commandOutput('git', ['log', '--oneline', '-5'], cwd)
|
|
189
186
|
: '',
|
|
@@ -198,8 +195,6 @@ export function createSystemPromptVariables(overrides = {}, opts = {}) {
|
|
|
198
195
|
hostname: stringOrEmpty(() => os.hostname()),
|
|
199
196
|
availableParallelism: numberOrEmpty(() => os.availableParallelism()),
|
|
200
197
|
totalMemory: numberOrEmpty(() => os.totalmem()),
|
|
201
|
-
freeMemory: numberOrEmpty(() => os.freemem()),
|
|
202
|
-
uptime: numberOrEmpty(() => os.uptime()),
|
|
203
198
|
},
|
|
204
199
|
runtime: {
|
|
205
200
|
nodeVersion: stringOrEmpty(() => process.version),
|
|
@@ -208,8 +203,6 @@ export function createSystemPromptVariables(overrides = {}, opts = {}) {
|
|
|
208
203
|
ppid: numberOrEmpty(() => process.ppid),
|
|
209
204
|
},
|
|
210
205
|
time: {
|
|
211
|
-
current: stringOrEmpty(() => now.toString()),
|
|
212
|
-
iso: stringOrEmpty(() => now.toISOString()),
|
|
213
206
|
date: currentDate(timeZone, now),
|
|
214
207
|
timezone: timeZone,
|
|
215
208
|
},
|
|
@@ -234,8 +227,6 @@ export function createSystemPromptVariables(overrides = {}, opts = {}) {
|
|
|
234
227
|
terminal: {
|
|
235
228
|
term: envString('TERM'),
|
|
236
229
|
colorTerm: envString('COLORTERM'),
|
|
237
|
-
columns: numberOrEmpty(() => process.stdout.columns),
|
|
238
|
-
rows: numberOrEmpty(() => process.stdout.rows),
|
|
239
230
|
},
|
|
240
231
|
filesystem: {
|
|
241
232
|
tmpdir: stringOrEmpty(() => os.tmpdir()),
|
|
@@ -48,7 +48,7 @@ function findEmptyExitPlanModeBlocks(content, out) {
|
|
|
48
48
|
* - Header 名规范:interceptor 走 fetch Headers.entries() 全小写(WHATWG 规范),
|
|
49
49
|
* 只查小写键即可。
|
|
50
50
|
* - In-place mutation by design:用 Object.assign(blk.input, patch) 而非
|
|
51
|
-
* `blk.input = {...}`。增量重建器 (
|
|
51
|
+
* `blk.input = {...}`。增量重建器 (@ccv/core/delta-reconstructor) 会让同一 tool_use
|
|
52
52
|
* block 在多个 entry 间共享对象引用;in-place mutate 让后续 entry 的「Object.keys
|
|
53
53
|
* (inp).length === 0」预检自动跳过——正是我们想要的 (相同 plan,不重新查盘)。
|
|
54
54
|
* 注意:此优化仅在 SSE / live 路径(共享对象)生效;REST 路径 raw → JSON.parse
|
|
@@ -138,7 +138,7 @@ export function ensureHooks() {
|
|
|
138
138
|
|
|
139
139
|
// AskUserQuestion hook → ask-bridge.js
|
|
140
140
|
// Guard: only execute when CCVIEWER_PORT is set (i.e. launched by cc-viewer)
|
|
141
|
-
const askBridgePath = resolve(SERVER_LIB, 'ask-bridge.js');
|
|
141
|
+
const askBridgePath = resolve(SERVER_LIB, 'ask', 'ask-bridge.js');
|
|
142
142
|
const askCmd = `[ -n "$CCVIEWER_PORT" ] && node "${askBridgePath}" || true ${CCV_HOOK_MARKER}`;
|
|
143
143
|
const askDesired = _buildHookObj(askCmd);
|
|
144
144
|
const askExisting = settings.hooks.PreToolUse.find(h => h.matcher === 'AskUserQuestion');
|
|
@@ -157,7 +157,7 @@ export function ensureHooks() {
|
|
|
157
157
|
|
|
158
158
|
// Permission approval hook → perm-bridge.js (matcher: "" = match all tools)
|
|
159
159
|
// Guard: only execute when CCVIEWER_PORT is set (i.e. launched by cc-viewer)
|
|
160
|
-
const permBridgePath = resolve(SERVER_LIB, 'perm-bridge.js');
|
|
160
|
+
const permBridgePath = resolve(SERVER_LIB, 'ask', 'perm-bridge.js');
|
|
161
161
|
const permCmd = `[ -n "$CCVIEWER_PORT" ] && node "${permBridgePath}" || true ${CCV_HOOK_MARKER}`;
|
|
162
162
|
const permMatcher = '';
|
|
163
163
|
// Clean up legacy entries
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
import { realpathSync } from 'node:fs';
|
|
14
14
|
import { resolve, basename, sep, join } from 'node:path';
|
|
15
15
|
import { homedir, platform, tmpdir } from 'node:os';
|
|
16
|
-
import { getClaudeConfigDir } from '../../findcc.js';
|
|
16
|
+
import { getClaudeConfigDir, onLogDirChange } from '../../findcc.js';
|
|
17
17
|
import { loadWorkspaces } from '../workspace-registry.js';
|
|
18
18
|
|
|
19
19
|
const osPlatform = platform();
|
|
@@ -105,6 +105,11 @@ export function bumpWorkspacesVersion() {
|
|
|
105
105
|
_rootsCache = null;
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
+
// LOG_DIR changes relocate the workspace registry file — the allowlist cache
|
|
109
|
+
// (including registered workspaces) must be invalidated. Registered at module
|
|
110
|
+
// load so findcc (a leaf) never imports this module.
|
|
111
|
+
onLogDirChange(() => bumpWorkspacesVersion());
|
|
112
|
+
|
|
108
113
|
/**
|
|
109
114
|
* 测试 / 多 process 场景显式重置 —— 测试可在更换 HOME env 后调,policy 重新解析。
|
|
110
115
|
*/
|
package/server/lib/file-api.js
CHANGED
|
@@ -5,6 +5,22 @@
|
|
|
5
5
|
import { resolve, join, sep, isAbsolute } from 'node:path';
|
|
6
6
|
import { realpathSync, existsSync, statSync, readFileSync, writeFileSync, renameSync } from 'node:fs';
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* A path counts as a non-empty file only if it exists, is a regular file, and
|
|
10
|
+
* has size > 0 (an empty file would blank the system prompt — skipping is safer).
|
|
11
|
+
* Bad symlinks / missing paths / directories → statSync throws or isFile()=false → false.
|
|
12
|
+
* Shared leaf home (moved from system-prompt-files.js to break the
|
|
13
|
+
* model-system-prompts.js ↔ system-prompt-files.js static cycle).
|
|
14
|
+
*/
|
|
15
|
+
export function isNonEmptyFile(p) {
|
|
16
|
+
try {
|
|
17
|
+
const st = statSync(p);
|
|
18
|
+
return st.isFile() && st.size > 0;
|
|
19
|
+
} catch {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
8
24
|
/**
|
|
9
25
|
* Check whether targetPath is contained within the project root directory.
|
|
10
26
|
* Resolves symlinks via realpathSync. Returns false on any error.
|
|
@@ -31,7 +47,7 @@ class FileApiError extends Error {
|
|
|
31
47
|
/**
|
|
32
48
|
* Resolve and validate a file path. No production callers (readFileContent does its own inline
|
|
33
49
|
* path validation); kept as a standalone, path-traversal-defending helper covered by
|
|
34
|
-
* test/file-api-gap.test.js — don't delete as "dead code" without removing that test.
|
|
50
|
+
* packages/app/test/file-api-gap.test.js — don't delete as "dead code" without removing that test.
|
|
35
51
|
* @param {string} cwd - project working directory
|
|
36
52
|
* @param {string} reqPath - requested path (relative or absolute)
|
|
37
53
|
* @param {boolean} isEditorSession - whether this is an editor session
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// and the existing dingtalk-bridge tests keep working unchanged. Importing it registers the
|
|
7
7
|
// DingTalk adapter with the core.
|
|
8
8
|
import * as core from './im-bridge-core.js';
|
|
9
|
-
import { __setClientFactory } from '
|
|
9
|
+
import { __setClientFactory } from '../adapters/dingtalk-adapter.js';
|
|
10
10
|
|
|
11
11
|
const ID = 'dingtalk';
|
|
12
12
|
|
|
@@ -12,14 +12,14 @@
|
|
|
12
12
|
// 用 openSync(path,'wx') 原子创建:从不覆盖用户已编辑的文件(避免 existsSync→write 的 TOCTOU)。因此
|
|
13
13
|
// 语言在「首次创建」时定格,之后换语言不会自动重写——重置/换语言由编辑器「恢复默认」(writeImAppendSystem) 触发。
|
|
14
14
|
// 对比 server/lib/im-skills.js(内置技能):那边是「受管同步」每次启动按包内版本覆盖内容;本模块相反,wx 创建后永不覆盖。
|
|
15
|
-
import { openSync, writeFileSync, closeSync, mkdirSync, readFileSync, unlinkSync,
|
|
15
|
+
import { openSync, writeFileSync, closeSync, mkdirSync, readFileSync, unlinkSync, lstatSync } from 'node:fs';
|
|
16
16
|
import { join } from 'node:path';
|
|
17
17
|
import { randomBytes } from 'node:crypto';
|
|
18
18
|
import { imDir } from './im-lock.js';
|
|
19
|
-
import { renameSyncWithRetry } from '
|
|
20
|
-
import { IM_PRESET_DIR } from '
|
|
19
|
+
import { renameSyncWithRetry, isNonEmptyFile } from '../file-api.js';
|
|
20
|
+
import { IM_PRESET_DIR } from '../../_paths.js';
|
|
21
21
|
import { resolvePrefLang } from './im-lang.js';
|
|
22
|
-
import { APPEND_SYSTEM_PROMPT_FILE } from '
|
|
22
|
+
import { APPEND_SYSTEM_PROMPT_FILE } from '../system-prompt-files.js';
|
|
23
23
|
|
|
24
24
|
// 写入上限(字符数,按 String.length / UTF-16 码元计):远超任何合理人格定义,纯防失控大 body。
|
|
25
25
|
export const MAX_IM_APPEND_SYSTEM_CHARS = 256 * 1024;
|
|
@@ -42,15 +42,7 @@ export function platformLabel(id, lang = resolvePrefLang(DEFAULT_LANG)) {
|
|
|
42
42
|
return (typeof lang === 'string' && lang.startsWith('zh')) ? m.zh : m.default;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
// 文件存在、是普通文件且非空(size>0)
|
|
46
|
-
function isNonEmptyFile(p) {
|
|
47
|
-
try {
|
|
48
|
-
const st = statSync(p);
|
|
49
|
-
return st.isFile() && st.size > 0;
|
|
50
|
-
} catch {
|
|
51
|
-
return false;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
45
|
+
// 文件存在、是普通文件且非空(size>0)才算「已有内容」——共享实现:../file-api.js。
|
|
54
46
|
|
|
55
47
|
// 极简兜底:当 server/imPreset/<lang>.md 与 zh.md 都读不到时(理论上不会发生),至少给一份最小约束,避免崩。
|
|
56
48
|
function fallbackPreset(P, id) {
|
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
// a per-instance scratch object (token cache, send client) cleared on reset.
|
|
22
22
|
import { existsSync, readFileSync, appendFileSync } from 'node:fs';
|
|
23
23
|
import { join } from 'node:path';
|
|
24
|
-
import { LOG_DIR } from '
|
|
25
|
-
import { t } from '
|
|
24
|
+
import { LOG_DIR } from '../../../findcc.js';
|
|
25
|
+
import { t } from '../../i18n.js';
|
|
26
26
|
import { upsertSender } from './im-senders.js';
|
|
27
27
|
|
|
28
28
|
// ─── tunables (shared across platforms; per-platform rate caps come from adapter.rateLimit) ───
|
|
@@ -361,9 +361,9 @@ function audit(inst, event, data) {
|
|
|
361
361
|
} catch { /* best-effort */ }
|
|
362
362
|
}
|
|
363
363
|
|
|
364
|
-
/** Bracketed-paste + submit, matching the frontend's ptyChunkBuilder.
|
|
365
|
-
*
|
|
366
|
-
function bracketPasteSubmit(text) {
|
|
364
|
+
/** Bracketed-paste + submit, matching the frontend's ptyChunkBuilder. Exported for
|
|
365
|
+
* chat-queue.js (the chat-composer busy queue shares the exact same inject framing). */
|
|
366
|
+
export function bracketPasteSubmit(text) {
|
|
367
367
|
return ['\x1b[200~' + text + '\x1b[201~', '\r'];
|
|
368
368
|
}
|
|
369
369
|
|
|
@@ -385,13 +385,19 @@ function markOrigin(id, senderId, content) {
|
|
|
385
385
|
* Claude TUI. CR is removed too: it is the submit key, so leaving it in inbound text would be a
|
|
386
386
|
* submit byte smuggled into the paste frame.
|
|
387
387
|
*/
|
|
388
|
-
function sanitizeInbound(text) {
|
|
388
|
+
export function sanitizeInbound(text) {
|
|
389
389
|
return String(text)
|
|
390
390
|
.replace(/\x1b\[20[01]~/g, '')
|
|
391
391
|
// eslint-disable-next-line no-control-regex
|
|
392
392
|
.replace(/[\x00-\x08\x0b-\x1f\x7f]/g, '');
|
|
393
393
|
}
|
|
394
394
|
|
|
395
|
+
/** Cross-module injection mutex probe: chat-queue.js consults this before injecting into the
|
|
396
|
+
* shared PTY so a chat-composer inject and an IM-bridge inject can never interleave. */
|
|
397
|
+
export function anyActiveInjection() {
|
|
398
|
+
return !!activeInjection;
|
|
399
|
+
}
|
|
400
|
+
|
|
395
401
|
function remember(inst, msgId) {
|
|
396
402
|
if (!msgId) return false;
|
|
397
403
|
if (inst.seenMsgIds.includes(msgId)) return true;
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
// admin API masks secret fields entirely (→ hasSecret).
|
|
14
14
|
import { existsSync, readFileSync, writeFileSync, mkdirSync, chmodSync } from 'node:fs';
|
|
15
15
|
import { join, dirname } from 'node:path';
|
|
16
|
-
import { LOG_DIR } from '
|
|
16
|
+
import { LOG_DIR } from '../../../findcc.js';
|
|
17
17
|
|
|
18
18
|
const MIN_CHUNK = 500;
|
|
19
19
|
const MAX_CHUNK = 5000;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// 供 IM 内置技能注入(im-skills.js)与人格预置(im-append-system.js)共用,避免各自重复读 preferences。
|
|
3
3
|
import { readFileSync } from 'node:fs';
|
|
4
4
|
import { join } from 'node:path';
|
|
5
|
-
import { LOG_DIR } from '
|
|
5
|
+
import { LOG_DIR } from '../../../findcc.js';
|
|
6
6
|
|
|
7
7
|
/** 读 preferences.lang;读不到 / 无字段 / 解析失败一律回退 def(默认 zh)。 */
|
|
8
8
|
export function resolvePrefLang(def = 'zh') {
|
|
@@ -12,8 +12,8 @@ import { openSync, closeSync, readFileSync, writeFileSync, unlinkSync, mkdirSync
|
|
|
12
12
|
import { join } from 'node:path';
|
|
13
13
|
import { randomBytes } from 'node:crypto';
|
|
14
14
|
import { get as httpGet } from 'node:http';
|
|
15
|
-
import { LOG_DIR } from '
|
|
16
|
-
import { renameSyncWithRetry } from '
|
|
15
|
+
import { LOG_DIR } from '../../../findcc.js';
|
|
16
|
+
import { renameSyncWithRetry } from '../file-api.js';
|
|
17
17
|
|
|
18
18
|
// 启动窗:已建锁但尚未回填 port 的进程,在此时间内视为"启动中"(不可被判死/重拉)。
|
|
19
19
|
export const BOOT_WINDOW_MS = 15000;
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
imDir, readImLock, clearImLock, isPidAlive, getImLiveness, defaultProbe,
|
|
15
15
|
} from './im-lock.js';
|
|
16
16
|
|
|
17
|
-
const CLI_JS = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..', 'cli.js');
|
|
17
|
+
const CLI_JS = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..', '..', 'cli.js');
|
|
18
18
|
|
|
19
19
|
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
20
20
|
|
|
@@ -11,7 +11,7 @@ import { openSync, closeSync, readFileSync, writeFileSync, unlinkSync, mkdirSync
|
|
|
11
11
|
import { join } from 'node:path';
|
|
12
12
|
import { randomBytes } from 'node:crypto';
|
|
13
13
|
import { imDir } from './im-lock.js';
|
|
14
|
-
import { renameSyncWithRetry } from '
|
|
14
|
+
import { renameSyncWithRetry } from '../file-api.js';
|
|
15
15
|
|
|
16
16
|
export const MAX_SENDERS = 500;
|
|
17
17
|
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
13
13
|
import { join, dirname } from 'node:path';
|
|
14
14
|
import { randomBytes } from 'node:crypto';
|
|
15
|
-
import { IM_SKILLS_DIR } from '
|
|
15
|
+
import { IM_SKILLS_DIR } from '../../_paths.js';
|
|
16
16
|
import { imDir } from './im-lock.js';
|
|
17
|
-
import { renameSyncWithRetry } from '
|
|
17
|
+
import { renameSyncWithRetry } from '../file-api.js';
|
|
18
18
|
import { resolvePrefLang } from './im-lang.js';
|
|
19
19
|
|
|
20
20
|
export const BUILTIN_SKILL_NAME = 'manage-ccv-projects';
|
|
@@ -10,8 +10,8 @@ const SUBAGENT_BILLING_RE = /cc_is_subagent=true\b/;
|
|
|
10
10
|
// 同进程 Agent/Task 队友(teammate):system prompt 注入团队协作标记,但继承完整 "You are Claude Code"
|
|
11
11
|
// prompt + Edit/Bash/Task 工具,且不带 --agent-name 进程参数(_isTeammate 认不出),会误中下方 MainAgent
|
|
12
12
|
// 启发式 → 流式期间被当 mainAgent 开 live-stream,其 thinking 污染主「最新回复」overlay。须显式排除。
|
|
13
|
-
// KEEP IN SYNC: server/lib/kv-cache-analyzer.js +
|
|
14
|
-
// 两处服务端实现(本文件 + kv-cache-analyzer)由 test/interceptor-core-mainagent.test.js 互校防漂移;
|
|
13
|
+
// KEEP IN SYNC: server/lib/kv-cache-analyzer.js + @ccv/core/contentFilter(三处判据必须一致)。
|
|
14
|
+
// 两处服务端实现(本文件 + kv-cache-analyzer)由 packages/app/test/interceptor-core-mainagent.test.js 互校防漂移;
|
|
15
15
|
// 前端 contentFilter 那份由 test/content-filter-unit.test.js 单测覆盖。
|
|
16
16
|
const TEAMMATE_SYSTEM_RE = /running as an agent in a team|Agent Teammate Communication/i;
|
|
17
17
|
// 1.7.0: the last external consumer (teammate-detect.js) retired with the
|
|
@@ -21,8 +21,8 @@ export { TEAMMATE_SYSTEM_RE, SUBAGENT_BILLING_RE };
|
|
|
21
21
|
|
|
22
22
|
// Rotation carry-forward: prompt-prefix → teammate-name pairs extracted from a
|
|
23
23
|
// mainAgent response body's Agent tool_use blocks. Prefix normalization MUST
|
|
24
|
-
// match
|
|
25
|
-
// pinned by test/interceptor.test.js parity cases.
|
|
24
|
+
// match @ccv/core/contentFilter (trimStart BEFORE slice, length 60) —
|
|
25
|
+
// pinned by packages/app/test/interceptor.test.js parity cases.
|
|
26
26
|
export const TEAMMATE_PROMPT_PREFIX_LEN = 60;
|
|
27
27
|
|
|
28
28
|
export function extractAgentSpawnPairs(responseBody) {
|
|
@@ -58,7 +58,10 @@ export function isMainAgentRequest(body) {
|
|
|
58
58
|
if (TEAMMATE_SYSTEM_RE.test(sysText)) return false;
|
|
59
59
|
// cc_is_subagent=true ⇒ 子代理,绝非 MainAgent(cc_version 2.1.181+)。从源头让新日志的 mainAgent 字段为 false。
|
|
60
60
|
if (SUBAGENT_BILLING_RE.test(sysText)) return false;
|
|
61
|
-
|
|
61
|
+
// SDK 模式(ccv -SDK)主会话 base prompt 是 "...built on Anthropic's Claude Agent SDK.",
|
|
62
|
+
// 非 CLI 的 "You are Claude Code"。SDK 子代理同用该 prompt,由下方工具启发式(缺 Agent/Task)排除;
|
|
63
|
+
// native teammate 已由 TEAMMATE_SYSTEM_RE 排除。用精确子串,勿放宽成 "You are a Claude agent"(误中 teammate)。
|
|
64
|
+
if (!sysText.includes('You are Claude Code') && !sysText.includes("built on Anthropic's Claude Agent SDK")) return false;
|
|
62
65
|
if (SUBAGENT_SYSTEM_RE.test(sysText)) return false;
|
|
63
66
|
|
|
64
67
|
const isSystemArray = Array.isArray(body.system);
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Server-side KV-Cache content analyzer.
|
|
3
|
-
* Ported from src/utils/helpers.js +
|
|
3
|
+
* Ported from apps/web/src/utils/helpers.js + @ccv/core/contentFilter
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { formatToolAsXml } from '
|
|
6
|
+
import { formatToolAsXml } from '@ccv/core/tools-xml-formatter';
|
|
7
7
|
export { formatToolAsXml };
|
|
8
8
|
|
|
9
9
|
const SUBAGENT_SYSTEM_RE = /command execution specialist|file search specialist|planning specialist|general-purpose agent|security monitor|performing a web search/i;
|
|
10
10
|
// cc_version 2.1.181+: billing header marks subagents (cc_is_subagent=true); genuine main omits it (never =false).
|
|
11
11
|
// Such subagents inherit the full "You are Claude Code" prompt + Edit/Bash/Agent tools and would otherwise hit the
|
|
12
|
-
// lightweight heuristic below. \b anchor avoids matching =truex. KEEP IN SYNC with
|
|
12
|
+
// lightweight heuristic below. \b anchor avoids matching =truex. KEEP IN SYNC with @ccv/core/contentFilter + interceptor-core.js.
|
|
13
13
|
const SUBAGENT_BILLING_RE = /cc_is_subagent=true\b/;
|
|
14
14
|
const TEAMMATE_SYSTEM_RE = /running as an agent in a team|Agent Teammate Communication/i;
|
|
15
15
|
|
|
@@ -47,7 +47,8 @@ export function isMainAgentEntry(entry) {
|
|
|
47
47
|
const body = entry.body || {};
|
|
48
48
|
if (!body.system || !Array.isArray(body.tools)) return false;
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
// SDK 模式(ccv -SDK)主会话 base prompt 含 "built on Anthropic's Claude Agent SDK."(同 interceptor-core.js 对齐)。
|
|
51
|
+
if (!sysText.includes('You are Claude Code') && !sysText.includes("built on Anthropic's Claude Agent SDK")) return false;
|
|
51
52
|
if (SUBAGENT_SYSTEM_RE.test(sysText)) return false;
|
|
52
53
|
|
|
53
54
|
// New architecture (v2.1.69+): deferred tool loading
|
|
@@ -165,7 +166,7 @@ export function extractCachedContent(entry) {
|
|
|
165
166
|
// tools: API caches in order tools → system → messages.
|
|
166
167
|
// Tools are implicitly cached as part of the prefix (no cache_control needed on tools themselves).
|
|
167
168
|
// Show tools when system has cached content (indicating a cache prefix exists).
|
|
168
|
-
// Keep in sync with src/utils/helpers.js extractCachedContent
|
|
169
|
+
// Keep in sync with apps/web/src/utils/helpers.js extractCachedContent
|
|
169
170
|
if (Array.isArray(body.tools) && body.tools.length > 0 && result.system.length > 0) {
|
|
170
171
|
for (const tool of body.tools) {
|
|
171
172
|
result.tools.push(formatToolAsXml(tool));
|