@jingyi0605/codingns4dsh 0.1.0 → 0.1.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.en.md +306 -0
- package/README.md +190 -993
- package/data/build/dist/client/account-bar.d.ts +2 -2
- package/data/build/dist/client/account-bar.js +96 -39
- package/data/build/dist/client/bundle.js +13722 -3611
- package/data/build/dist/client/cli-catalog.js +20 -3
- package/data/build/dist/client/cli-slots.d.ts +5 -0
- package/data/build/dist/client/cli-slots.js +57 -7
- package/data/build/dist/client/debug/ui.d.ts +1 -1
- package/data/build/dist/client/debug/ui.js +62 -32
- package/data/build/dist/client/dsh-runtime-version.d.ts +9 -2
- package/data/build/dist/client/dsh-runtime-version.js +24 -2
- package/data/build/dist/client/features/cli-adapters.d.ts +1 -1
- package/data/build/dist/client/features/cli-adapters.js +19 -16
- package/data/build/dist/client/features/debug.js +2 -2
- package/data/build/dist/client/features/index.d.ts +2 -1
- package/data/build/dist/client/features/index.js +3 -1
- package/data/build/dist/client/features/lan-access-panel.d.ts +1 -1
- package/data/build/dist/client/features/lan-access-panel.js +8 -10
- package/data/build/dist/client/features/lan-access.js +1 -1
- package/data/build/dist/client/features/login-protection-panel.d.ts +1 -1
- package/data/build/dist/client/features/login-protection-panel.js +7 -9
- package/data/build/dist/client/features/reverse-proxy-panel.d.ts +1 -1
- package/data/build/dist/client/features/reverse-proxy-panel.js +99 -11
- package/data/build/dist/client/features/reverse-proxy.d.ts +1 -1
- package/data/build/dist/client/features/reverse-proxy.js +19 -18
- package/data/build/dist/client/features/terminal-enhancement-panel.d.ts +1 -1
- package/data/build/dist/client/features/terminal-enhancement-panel.js +62 -55
- package/data/build/dist/client/features/terminal-enhancement.d.ts +1 -1
- package/data/build/dist/client/features/terminal-enhancement.js +3 -3
- package/data/build/dist/client/features/types.d.ts +14 -3
- package/data/build/dist/client/features/workspace-session-enhancement-panel.d.ts +1 -1
- package/data/build/dist/client/features/workspace-session-enhancement-panel.js +31 -9
- package/data/build/dist/client/features/workspace-session-enhancement.js +72 -11
- package/data/build/dist/client/git-management.d.ts +16 -0
- package/data/build/dist/client/git-management.js +757 -0
- package/data/build/dist/client/index.d.ts +3 -2
- package/data/build/dist/client/index.js +152 -27
- package/data/build/dist/client/locale.js +91 -29
- package/data/build/dist/client/quick-phrase-layout.d.ts +49 -0
- package/data/build/dist/client/quick-phrase-layout.js +95 -0
- package/data/build/dist/client/quick-phrase-slot.d.ts +7 -0
- package/data/build/dist/client/quick-phrase-slot.js +370 -0
- package/data/build/dist/client/remote-web-context.js +1 -1
- package/data/build/dist/client/settings-bridge.d.ts +9 -6
- package/data/build/dist/client/settings-bridge.js +51 -27
- package/data/build/dist/client/settings-section.d.ts +3 -2
- package/data/build/dist/client/settings-section.js +33 -19
- package/data/build/dist/client/subscription-slot.d.ts +3 -0
- package/data/build/dist/client/subscription-slot.js +108 -16
- package/data/build/dist/client/terminal/model.d.ts +14 -2
- package/data/build/dist/client/terminal/model.js +109 -21
- package/data/build/dist/client/terminal/recovery.d.ts +50 -0
- package/data/build/dist/client/terminal/recovery.js +101 -0
- package/data/build/dist/client/terminal/ui.d.ts +2 -2
- package/data/build/dist/client/terminal/ui.js +49 -11
- package/data/build/dist/client/terminal/xterm-view.d.ts +2 -2
- package/data/build/dist/client/terminal/xterm-view.js +2 -1
- package/data/build/dist/client/theme.d.ts +6 -1
- package/data/build/dist/client/theme.js +32 -1
- package/data/build/dist/client/workspace-session-archive-dom.d.ts +12 -0
- package/data/build/dist/client/workspace-session-archive-dom.js +27 -5
- package/data/build/dist/client/workspace-session-visibility-dom.d.ts +30 -0
- package/data/build/dist/client/workspace-session-visibility-dom.js +604 -0
- package/data/build/dist/dsh-capabilities/client/config-forms-adapter.d.ts +50 -0
- package/data/build/dist/dsh-capabilities/client/config-forms-adapter.js +139 -0
- package/data/build/dist/dsh-capabilities/client/conversation-adapter.d.ts +7 -0
- package/data/build/dist/dsh-capabilities/client/conversation-adapter.js +6 -0
- package/data/build/dist/dsh-capabilities/client/locale-adapter.d.ts +9 -0
- package/data/build/dist/dsh-capabilities/client/locale-adapter.js +4 -0
- package/data/build/dist/dsh-capabilities/client/primitives-adapter.d.ts +10 -0
- package/data/build/dist/dsh-capabilities/client/primitives-adapter.js +14 -0
- package/data/build/dist/dsh-capabilities/client/settings-scope-adapter.d.ts +8 -0
- package/data/build/dist/dsh-capabilities/client/settings-scope-adapter.js +16 -0
- package/data/build/dist/dsh-capabilities/client/sidebar-adapter.d.ts +7 -0
- package/data/build/dist/dsh-capabilities/client/sidebar-adapter.js +5 -0
- package/data/build/dist/dsh-capabilities/client/theme-adapter.d.ts +6 -0
- package/data/build/dist/dsh-capabilities/client/theme-adapter.js +4 -0
- package/data/build/dist/dsh-capabilities/client/typert-adapter.d.ts +5 -0
- package/data/build/dist/dsh-capabilities/client/typert-adapter.js +4 -0
- package/data/build/dist/dsh-capabilities/host/config-forms-adapter.d.ts +19 -0
- package/data/build/dist/dsh-capabilities/host/config-forms-adapter.js +45 -0
- package/data/build/dist/dsh-capabilities/host/connection-rpc-adapter.d.ts +19 -0
- package/data/build/dist/dsh-capabilities/host/connection-rpc-adapter.js +13 -0
- package/data/build/dist/dsh-capabilities/host/settings-scope-adapter.d.ts +8 -0
- package/data/build/dist/dsh-capabilities/host/settings-scope-adapter.js +47 -0
- package/data/build/dist/dsh-capabilities/host/typert-adapter.d.ts +6 -0
- package/data/build/dist/dsh-capabilities/host/typert-adapter.js +4 -0
- package/data/build/dist/dsh-capabilities/index.d.ts +6 -0
- package/data/build/dist/dsh-capabilities/index.js +6 -0
- package/data/build/dist/dsh-capabilities/matrix.d.ts +15 -0
- package/data/build/dist/dsh-capabilities/matrix.js +32 -0
- package/data/build/dist/dsh-capabilities/registry.d.ts +22 -0
- package/data/build/dist/dsh-capabilities/registry.js +196 -0
- package/data/build/dist/dsh-capabilities/routes.d.ts +10 -0
- package/data/build/dist/dsh-capabilities/routes.js +34 -0
- package/data/build/dist/dsh-capabilities/settings-store.d.ts +29 -0
- package/data/build/dist/dsh-capabilities/settings-store.js +5 -0
- package/data/build/dist/dsh-capabilities/types.d.ts +50 -0
- package/data/build/dist/dsh-capabilities/types.js +23 -0
- package/data/build/dist/features/registry.d.ts +8 -2
- package/data/build/dist/features/registry.js +104 -1
- package/data/build/dist/host/auth-session.d.ts +8 -1
- package/data/build/dist/host/auth-session.js +28 -6
- package/data/build/dist/host/cli-adapters/claude-driver.d.ts +2 -0
- package/data/build/dist/host/cli-adapters/claude-driver.js +19 -4
- package/data/build/dist/host/cli-adapters/claude-model-options.d.ts +14 -0
- package/data/build/dist/host/cli-adapters/claude-model-options.js +157 -0
- package/data/build/dist/host/cli-adapters/codex-driver.d.ts +11 -0
- package/data/build/dist/host/cli-adapters/codex-driver.js +166 -14
- package/data/build/dist/host/cli-adapters/driver.d.ts +2 -0
- package/data/build/dist/host/cli-adapters/dsh-message-projector.d.ts +15 -0
- package/data/build/dist/host/cli-adapters/dsh-message-projector.js +120 -29
- package/data/build/dist/host/cli-adapters/dsh-tool-history.d.ts +4 -1
- package/data/build/dist/host/cli-adapters/dsh-tool-history.js +25 -7
- package/data/build/dist/host/cli-adapters/feature.js +74 -8
- package/data/build/dist/host/cli-adapters/gemini-driver.js +2 -2
- package/data/build/dist/host/cli-adapters/grok-driver.js +2 -2
- package/data/build/dist/host/cli-adapters/json-rpc-process.d.ts +4 -2
- package/data/build/dist/host/cli-adapters/json-rpc-process.js +8 -9
- package/data/build/dist/host/cli-adapters/kimi-driver.js +1 -1
- package/data/build/dist/host/cli-adapters/legacy-session-adapter.d.ts +17 -0
- package/data/build/dist/host/cli-adapters/legacy-session-adapter.js +88 -0
- package/data/build/dist/host/cli-adapters/legacy-session-settings.d.ts +24 -0
- package/data/build/dist/host/cli-adapters/legacy-session-settings.js +162 -0
- package/data/build/dist/host/cli-adapters/official-provider-subscription.d.ts +29 -0
- package/data/build/dist/host/cli-adapters/official-provider-subscription.js +361 -0
- package/data/build/dist/host/cli-adapters/opencode-driver.d.ts +2 -0
- package/data/build/dist/host/cli-adapters/opencode-driver.js +97 -12
- package/data/build/dist/host/cli-adapters/pi-driver.js +69 -23
- package/data/build/dist/host/cli-adapters/provider-registry.d.ts +33 -0
- package/data/build/dist/host/cli-adapters/provider-registry.js +83 -0
- package/data/build/dist/host/cli-adapters/provider-subscription.d.ts +25 -3
- package/data/build/dist/host/cli-adapters/provider-subscription.js +346 -30
- package/data/build/dist/host/cli-adapters/registry.d.ts +6 -0
- package/data/build/dist/host/cli-adapters/registry.js +170 -13
- package/data/build/dist/host/cli-adapters/rpc-driver-utils.js +10 -0
- package/data/build/dist/host/cli-adapters/session-store.d.ts +7 -0
- package/data/build/dist/host/cli-adapters/session-store.js +39 -1
- package/data/build/dist/host/cli-adapters/standard-stream-driver.d.ts +3 -0
- package/data/build/dist/host/cli-adapters/stream-normalizer.d.ts +3 -0
- package/data/build/dist/host/cli-adapters/stream-normalizer.js +22 -2
- package/data/build/dist/host/control-api-client.d.ts +3 -3
- package/data/build/dist/host/control-api-client.js +2 -1
- package/data/build/dist/host/credential-store.js +11 -1
- package/data/build/dist/host/dsh-device-runtime.d.ts +4 -0
- package/data/build/dist/host/dsh-device-runtime.js +20 -9
- package/data/build/dist/host/dsh-runtime-version.d.ts +3 -2
- package/data/build/dist/host/dsh-runtime-version.js +71 -2
- package/data/build/dist/host/features/auth.js +8 -5
- package/data/build/dist/host/features/debug.js +1 -1
- package/data/build/dist/host/features/git-management.d.ts +5 -0
- package/data/build/dist/host/features/git-management.js +290 -0
- package/data/build/dist/host/features/host-status.js +1 -1
- package/data/build/dist/host/features/index.d.ts +1 -0
- package/data/build/dist/host/features/index.js +3 -0
- package/data/build/dist/host/features/terminal-process.js +1 -1
- package/data/build/dist/host/features/terminal-status.d.ts +3 -1
- package/data/build/dist/host/features/terminal-status.js +3 -1
- package/data/build/dist/host/index.d.ts +7 -3
- package/data/build/dist/host/index.js +79 -15
- package/data/build/dist/host/lan-access-dsh.js +18 -5
- package/data/build/dist/host/native-session-bridge.d.ts +23 -1
- package/data/build/dist/host/native-session-bridge.js +157 -10
- package/data/build/dist/host/rpc-table.d.ts +1 -1
- package/data/build/dist/host/rpc.js +60 -10
- package/data/build/dist/host/session-migration-repair.d.ts +19 -0
- package/data/build/dist/host/session-migration-repair.js +395 -0
- package/data/build/dist/host/settings.d.ts +8 -1
- package/data/build/dist/host/settings.js +94 -3
- package/data/build/dist/host/terminal/backends/tmux-backend.d.ts +1 -0
- package/data/build/dist/host/terminal/backends/tmux-backend.js +4 -2
- package/data/build/dist/host/terminal/controller-factory.d.ts +4 -0
- package/data/build/dist/host/terminal/controller-factory.js +26 -7
- package/data/build/dist/host/terminal/runtime-manager.d.ts +2 -1
- package/data/build/dist/host/terminal/runtime-manager.js +3 -0
- package/data/build/dist/host/terminal/startup.d.ts +2 -0
- package/data/build/dist/host/terminal/startup.js +2 -1
- package/data/build/dist/host/terminal/terminal-controller.d.ts +10 -3
- package/data/build/dist/host/terminal/terminal-controller.js +101 -15
- package/data/build/dist/host/terminal/terminal-process-service.js +3 -1
- package/data/build/dist/host/terminal/terminal-service.d.ts +2 -0
- package/data/build/dist/host/terminal/terminal-service.js +10 -0
- package/data/build/dist/index.d.ts +6 -2
- package/data/build/dist/index.js +8 -2
- package/data/build/dist/shared/contracts/cli-adapter.d.ts +14 -0
- package/data/build/dist/shared/contracts/config.d.ts +31 -1
- package/data/build/dist/shared/contracts/config.js +25 -0
- package/data/build/dist/shared/contracts/dsh-device.d.ts +13 -1
- package/data/build/dist/shared/contracts/errors.d.ts +1 -1
- package/data/build/dist/shared/contracts/feature.d.ts +6 -0
- package/data/build/dist/shared/contracts/git.d.ts +82 -0
- package/data/build/dist/shared/contracts/git.js +3 -0
- package/data/build/dist/shared/contracts/subscription.d.ts +46 -0
- package/data/build/dist/shared/contracts/terminal.d.ts +4 -1
- package/data/build/dist/shared/contracts/version.d.ts +2 -2
- package/data/build/dist/shared/contracts/version.js +4 -6
- package/data/build/dist/shared/debug.d.ts +14 -0
- package/data/build/dist/shared/debug.js +53 -0
- package/data/build/dist/shared/index.d.ts +7 -4
- package/data/build/dist/shared/index.js +2 -1
- package/data/build/dist/transport/debug.d.ts +1 -1
- package/data/build/dist/transport/debug.js +3 -30
- package/data/build/dist/transport/dsh-session.js +3 -3
- package/data/build/dist/typert.host.d.ts +1 -1
- package/data/build/dist/typert.host.js +6 -3
- package/data/build/dist/typert.remote-client.d.ts +11 -0
- package/data/build/dist/typert.remote-client.js +7 -0
- package/dsh.bundle.patch +1 -1
- package/package.json +13 -5
- package/profile/README.md +4 -4
- package/profile/package.json +6 -4
- package/profile/scripts/check-dsh-install.mjs +2 -2
- package/profile/version.json +2 -2
- package/scripts/check-dsh-install.mjs +2 -2
- package/version.json +2 -2
|
@@ -7,17 +7,21 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import type { Context } from '@deepseek-ai/cordis';
|
|
9
9
|
export declare function apply(ctx?: Context): void;
|
|
10
|
-
export { HOST_FEATURES, createAuthFeature, createLanAccessDshFeature, createTerminalStatusFeature, createHostFeatures, createCliAdaptersFeature, createTerminalProcessFeature, } from './features/index.js';
|
|
10
|
+
export { HOST_FEATURES, createAuthFeature, createLanAccessDshFeature, createTerminalStatusFeature, createHostFeatures, createCliAdaptersFeature, createTerminalProcessFeature, createGitManagementFeature, } from './features/index.js';
|
|
11
11
|
export type { CodingNsHostServices } from './features/index.js';
|
|
12
12
|
export { CodingNsSettingsSchema, registerCodingNsSettings } from './settings.js';
|
|
13
13
|
export { createCodingNsRpcHandler, createCodingNsSettingsRpcHandler, registerCodingNsRpc } from './rpc.js';
|
|
14
14
|
export { DebugWorkspaceService, NodeDebugPortInspector, type DebugPortCheck, type DebugPortInspector, type DebugPortProcess, type DebugProxyBinding, } from './debug.js';
|
|
15
15
|
export { CodingNsRpcError, CodingNsRpcTable, type CodingNsRpcHandler, type CodingNsRpcTarget, } from './rpc-table.js';
|
|
16
16
|
export { CodingNsAuthSession } from './auth-session.js';
|
|
17
|
-
export { createCodingNsNativeSessionBridge, type CodingNsNativeSessionBridge, type CodingNsNativeSessionController, type CodingNsNativeSessionStore, type CodingNsNativeWorkspaceController, type CodingNsNativeRequestContext, } from './native-session-bridge.js';
|
|
17
|
+
export { createCodingNsNativeSessionBridge, type CodingNsNativeSessionBridge, type CodingNsNativeSessionController, type CodingNsNativeSessionStore, type CodingNsNativeWorkspaceController, type CodingNsNativeRequestContext, type CodingNsNativeUsageSample, } from './native-session-bridge.js';
|
|
18
|
+
export { repairLegacySessionLog, repairLegacySessionLogs, type LegacySessionRepairOptions, type LegacySessionRepairReport, } from './session-migration-repair.js';
|
|
19
|
+
export { defaultLegacySettingsPath, parseLegacyImportedSessionRecords, readLegacyImportedSessionRecords, } from './cli-adapters/legacy-session-settings.js';
|
|
18
20
|
export { CommandCodeDriver } from './cli-adapters/command-code-driver.js';
|
|
19
21
|
export { CommandCodeSubscriptionService, readCommandCodeApiKey } from './cli-adapters/command-code-subscription.js';
|
|
20
|
-
export { ProviderSubscriptionService, CodexSubscriptionService, ClaudeCodeSubscriptionService, Sub2ApiUsageService, OpenCodeSubscriptionService, type Sub2ApiSource, type Sub2ApiUsageOptions, } from './cli-adapters/provider-subscription.js';
|
|
22
|
+
export { ProviderSubscriptionService, CodexSubscriptionService, ClaudeCodeSubscriptionService, DeepseekSubscriptionService, Sub2ApiUsageService, OpenCodeSubscriptionService, type DeepseekSubscriptionOptions, type Sub2ApiSource, type Sub2ApiUsageOptions, } from './cli-adapters/provider-subscription.js';
|
|
23
|
+
export { OfficialProviderSubscriptionService, type OfficialProviderSubscriptionOptions } from './cli-adapters/official-provider-subscription.js';
|
|
24
|
+
export { MODEL_PROVIDER_DEFINITIONS, identifyModelProvider, normalizeProviderBaseUrl, normalizeProviderName, thirdPartyProvider, type ProviderDefinition, type ProviderIdentity, type ProviderSubscriptionCapability, type ProviderSubscriptionReader, } from './cli-adapters/provider-registry.js';
|
|
21
25
|
export { ClaudeCodeDriver } from './cli-adapters/claude-driver.js';
|
|
22
26
|
export { KimiCliDriver } from './cli-adapters/kimi-driver.js';
|
|
23
27
|
export { GeminiCliDriver } from './cli-adapters/gemini-driver.js';
|
|
@@ -8,30 +8,76 @@ import { createCodingNsNativeSessionBridge } from './native-session-bridge.js';
|
|
|
8
8
|
import { installTerminalController } from './terminal/startup.js';
|
|
9
9
|
import { DebugWorkspaceService } from './debug.js';
|
|
10
10
|
import { detectRuntimeDshVersion, DSH_VERSION_INJECTION_NAME } from './dsh-runtime-version.js';
|
|
11
|
+
import { createDshCapabilityRegistry } from '../dsh-capabilities/index.js';
|
|
12
|
+
import { debugInfo } from '../shared/debug.js';
|
|
13
|
+
import { repairLegacySessionLogs } from './session-migration-repair.js';
|
|
11
14
|
export function apply(ctx) {
|
|
12
15
|
if (ctx === undefined)
|
|
13
16
|
return;
|
|
14
17
|
const dshVersion = detectRuntimeDshVersion();
|
|
15
|
-
|
|
18
|
+
debugInfo('codingns4dsh: host apply entered', { dshVersion });
|
|
19
|
+
// DSH 0.1.7 的官方 v3->v4 迁移器要求每个 tool/call 先有 assistant/message
|
|
20
|
+
// 声明。旧版外部 Agent 曾直接写入 tool/call,必须在任何会话 open 前修复。
|
|
21
|
+
ctx.inject(['sessionPersistence'], async (sessionCtx) => {
|
|
22
|
+
const persistence = sessionCtx.get('sessionPersistence');
|
|
23
|
+
if (!isRecord(persistence) || typeof persistence.root !== 'string')
|
|
24
|
+
return;
|
|
25
|
+
const open = persistence.open;
|
|
26
|
+
if (typeof open !== 'function')
|
|
27
|
+
return;
|
|
28
|
+
let repair;
|
|
29
|
+
const repairBeforeOpen = () => {
|
|
30
|
+
repair ??= repairLegacySessionLogs({
|
|
31
|
+
root: persistence.root,
|
|
32
|
+
logger: (message, error) => console.warn('codingns4dsh:', message, error),
|
|
33
|
+
}).catch((error) => {
|
|
34
|
+
console.warn('codingns4dsh: 历史会话扫描失败', error);
|
|
35
|
+
return undefined;
|
|
36
|
+
});
|
|
37
|
+
return repair;
|
|
38
|
+
};
|
|
39
|
+
// DSH 的 v3->v4 转换发生在 persistence.open 内部。只在启动时异步扫描
|
|
40
|
+
// 会晚于第一次点击历史会话,因此必须把修复挂到真正的读取边界之前。
|
|
41
|
+
try {
|
|
42
|
+
persistence.open = async function (...args) {
|
|
43
|
+
await repairBeforeOpen();
|
|
44
|
+
return open.apply(this, args);
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
// 某些 Host 会冻结 Service 实例;启动扫描仍然可修复磁盘上的旧日志。
|
|
49
|
+
console.warn('codingns4dsh: 无法包装 sessionPersistence.open', error);
|
|
50
|
+
}
|
|
51
|
+
const report = await repairBeforeOpen();
|
|
52
|
+
debugInfo('codingns4dsh: legacy session repair finished', report);
|
|
53
|
+
});
|
|
16
54
|
ctx.inject(['settings', 'connection', 'webServer'], async (hostCtx) => {
|
|
17
|
-
|
|
55
|
+
debugInfo('codingns4dsh: host inject ready', {
|
|
18
56
|
hasConnection: hostCtx.connection !== undefined,
|
|
57
|
+
hasSettings: hostCtx.settings !== undefined,
|
|
58
|
+
hasWebServer: hostCtx.webServer !== undefined,
|
|
19
59
|
});
|
|
20
60
|
const webServerPort = hostCtx.webServer.port;
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
//
|
|
61
|
+
// Desktop 自己会通过 dshDesktopBoot 注入带 streamBaseUrl 的 __DSH_TRANSPORT__。
|
|
62
|
+
// 插件不能用只有 ownsHost 的对象覆盖它,否则 Desktop 的 /api/remote.mux
|
|
63
|
+
// 会退回 dsh-app://app 并返回 404。远程 iframe 的 transport 由自身桥接代码注入。
|
|
24
64
|
const indexInjectionEvents = hostCtx;
|
|
65
|
+
debugInfo('codingns4dsh: host index injection registration begin');
|
|
25
66
|
indexInjectionEvents.on('webserver/index-inject', (table) => {
|
|
26
|
-
table.push({ kind: 'global', name: '__DSH_TRANSPORT__', value: { ownsHost: true } });
|
|
27
67
|
table.push({ kind: 'global', name: DSH_VERSION_INJECTION_NAME, value: dshVersion });
|
|
28
68
|
});
|
|
69
|
+
debugInfo('codingns4dsh: host index injection registration ready');
|
|
70
|
+
debugInfo('codingns4dsh: host settings registration begin');
|
|
29
71
|
const settings = registerCodingNsSettings(hostCtx);
|
|
72
|
+
debugInfo('codingns4dsh: host settings registered');
|
|
73
|
+
const workspaceRoots = new Map();
|
|
30
74
|
// controller 必须在功能模块和浏览器 Client 开始消费状态前完成装配。
|
|
31
75
|
// 工厂在本次启动只读取一次开关,设置 watcher 不会热切同名 service。
|
|
32
76
|
const terminal = await installTerminalController(hostCtx, settings, hostCtx.settings, {
|
|
33
|
-
resolveWorkspaceRoot: (workspaceId) => resolveWorkspaceRoot(hostCtx, workspaceId),
|
|
77
|
+
resolveWorkspaceRoot: (workspaceId) => workspaceRoots.get(workspaceId) ?? resolveWorkspaceRoot(hostCtx, workspaceId),
|
|
78
|
+
registerWorkspaceRoot: (workspaceId, cwd) => workspaceRoots.set(workspaceId, cwd),
|
|
34
79
|
});
|
|
80
|
+
debugInfo('codingns4dsh: host terminal controller ready', { mode: terminal.mode });
|
|
35
81
|
const services = {
|
|
36
82
|
rpc: new CodingNsRpcTable(),
|
|
37
83
|
dshVersion,
|
|
@@ -40,9 +86,9 @@ export function apply(ctx) {
|
|
|
40
86
|
dshWebPort: webServerPort,
|
|
41
87
|
dshWebAuthenticatedUrl: hostCtx.connection.authenticatedUrl(`http://127.0.0.1:${String(webServerPort)}`),
|
|
42
88
|
events: { on: hostCtx.on.bind(hostCtx) },
|
|
43
|
-
nativeSessions: createCodingNsNativeSessionBridge(hostCtx),
|
|
89
|
+
nativeSessions: createCodingNsNativeSessionBridge(hostCtx, dshVersion),
|
|
44
90
|
terminalProcesses: terminal.processService,
|
|
45
|
-
resolveWorkspaceRoot: (workspaceId) => resolveWorkspaceRoot(hostCtx, workspaceId),
|
|
91
|
+
resolveWorkspaceRoot: (workspaceId) => workspaceRoots.get(workspaceId) ?? resolveWorkspaceRoot(hostCtx, workspaceId),
|
|
46
92
|
registerDebugProxyRoute: (handler) => hostCtx.connection.fetch.register({
|
|
47
93
|
path: '/api/codingns/debug-proxy',
|
|
48
94
|
methods: ['GET', 'HEAD', 'POST'],
|
|
@@ -51,22 +97,31 @@ export function apply(ctx) {
|
|
|
51
97
|
}),
|
|
52
98
|
};
|
|
53
99
|
const debug = new DebugWorkspaceService({
|
|
54
|
-
resolveWorkspaceRoot: (workspaceId) => resolveWorkspaceRoot(hostCtx, workspaceId),
|
|
100
|
+
resolveWorkspaceRoot: (workspaceId) => workspaceRoots.get(workspaceId) ?? resolveWorkspaceRoot(hostCtx, workspaceId),
|
|
55
101
|
terminalProcesses: terminal.processService,
|
|
56
102
|
});
|
|
57
103
|
const servicesWithDebug = { ...services, debug };
|
|
58
|
-
const
|
|
104
|
+
const capabilityProfile = createDshCapabilityRegistry(dshVersion, 'host', hostCtx).getProfile(hostCtx);
|
|
105
|
+
debugInfo('codingns4dsh: host capabilities resolved', {
|
|
106
|
+
dshVersion,
|
|
107
|
+
capabilities: [...capabilityProfile.capabilities.entries()].map(([capability, resolution]) => ({ capability, status: resolution.status, route: resolution.routeId, reason: resolution.reason ?? null })),
|
|
108
|
+
diagnostics: capabilityProfile.diagnostics,
|
|
109
|
+
});
|
|
110
|
+
const registry = new FeatureRegistry(servicesWithDebug, capabilityProfile);
|
|
59
111
|
registry.registerMany(createHostFeatures({
|
|
60
112
|
terminalStatus: {
|
|
61
113
|
controllerMode: terminal.mode,
|
|
62
114
|
effectiveEnabled: terminal.mode === 'enhanced',
|
|
115
|
+
runtimeTypes: terminal.runtimeTypes,
|
|
116
|
+
...(terminal.runtimeWarning === undefined ? {} : { runtimeWarning: terminal.runtimeWarning }),
|
|
63
117
|
},
|
|
64
118
|
}));
|
|
65
119
|
registry.validate();
|
|
120
|
+
debugInfo('codingns4dsh: host feature registry ready', { features: registry.descriptors().map((item) => item.name) });
|
|
66
121
|
const restartStates = captureRestartFeatureStates(registry.descriptors(), settings.get(), dshVersion);
|
|
67
122
|
try {
|
|
68
123
|
registerCodingNsRpc(hostCtx, services.rpc, services.settingsProvider);
|
|
69
|
-
|
|
124
|
+
debugInfo('codingns4dsh: host RPC registration requested');
|
|
70
125
|
}
|
|
71
126
|
catch (error) {
|
|
72
127
|
console.error('codingns4dsh: host RPC registration failed', error);
|
|
@@ -74,8 +129,10 @@ export function apply(ctx) {
|
|
|
74
129
|
}
|
|
75
130
|
hostCtx.effect(() => {
|
|
76
131
|
const sync = () => {
|
|
132
|
+
const enabled = enabledFeatureNames(registry.descriptors(), settings.get(), restartStates, dshVersion);
|
|
133
|
+
debugInfo('codingns4dsh: host feature sync', { enabled, states: registry.list() });
|
|
77
134
|
void registry
|
|
78
|
-
.reconcile(
|
|
135
|
+
.reconcile(enabled)
|
|
79
136
|
.catch((error) => {
|
|
80
137
|
console.error('codingns4dsh: 功能模块状态同步失败', error);
|
|
81
138
|
});
|
|
@@ -85,6 +142,9 @@ export function apply(ctx) {
|
|
|
85
142
|
}, 'codingns4dsh: 功能模块启停同步');
|
|
86
143
|
});
|
|
87
144
|
}
|
|
145
|
+
function isRecord(value) {
|
|
146
|
+
return typeof value === 'object' && value !== null;
|
|
147
|
+
}
|
|
88
148
|
function resolveWorkspaceRoot(ctx, workspaceId) {
|
|
89
149
|
try {
|
|
90
150
|
const registry = ctx.get('workspaceRegistry');
|
|
@@ -102,16 +162,20 @@ function resolveWorkspaceRoot(ctx, workspaceId) {
|
|
|
102
162
|
}
|
|
103
163
|
return null;
|
|
104
164
|
}
|
|
105
|
-
export { HOST_FEATURES, createAuthFeature, createLanAccessDshFeature, createTerminalStatusFeature, createHostFeatures, createCliAdaptersFeature, createTerminalProcessFeature, } from './features/index.js';
|
|
165
|
+
export { HOST_FEATURES, createAuthFeature, createLanAccessDshFeature, createTerminalStatusFeature, createHostFeatures, createCliAdaptersFeature, createTerminalProcessFeature, createGitManagementFeature, } from './features/index.js';
|
|
106
166
|
export { CodingNsSettingsSchema, registerCodingNsSettings } from './settings.js';
|
|
107
167
|
export { createCodingNsRpcHandler, createCodingNsSettingsRpcHandler, registerCodingNsRpc } from './rpc.js';
|
|
108
168
|
export { DebugWorkspaceService, NodeDebugPortInspector, } from './debug.js';
|
|
109
169
|
export { CodingNsRpcError, CodingNsRpcTable, } from './rpc-table.js';
|
|
110
170
|
export { CodingNsAuthSession } from './auth-session.js';
|
|
111
171
|
export { createCodingNsNativeSessionBridge, } from './native-session-bridge.js';
|
|
172
|
+
export { repairLegacySessionLog, repairLegacySessionLogs, } from './session-migration-repair.js';
|
|
173
|
+
export { defaultLegacySettingsPath, parseLegacyImportedSessionRecords, readLegacyImportedSessionRecords, } from './cli-adapters/legacy-session-settings.js';
|
|
112
174
|
export { CommandCodeDriver } from './cli-adapters/command-code-driver.js';
|
|
113
175
|
export { CommandCodeSubscriptionService, readCommandCodeApiKey } from './cli-adapters/command-code-subscription.js';
|
|
114
|
-
export { ProviderSubscriptionService, CodexSubscriptionService, ClaudeCodeSubscriptionService, Sub2ApiUsageService, OpenCodeSubscriptionService, } from './cli-adapters/provider-subscription.js';
|
|
176
|
+
export { ProviderSubscriptionService, CodexSubscriptionService, ClaudeCodeSubscriptionService, DeepseekSubscriptionService, Sub2ApiUsageService, OpenCodeSubscriptionService, } from './cli-adapters/provider-subscription.js';
|
|
177
|
+
export { OfficialProviderSubscriptionService } from './cli-adapters/official-provider-subscription.js';
|
|
178
|
+
export { MODEL_PROVIDER_DEFINITIONS, identifyModelProvider, normalizeProviderBaseUrl, normalizeProviderName, thirdPartyProvider, } from './cli-adapters/provider-registry.js';
|
|
115
179
|
export { ClaudeCodeDriver } from './cli-adapters/claude-driver.js';
|
|
116
180
|
export { KimiCliDriver } from './cli-adapters/kimi-driver.js';
|
|
117
181
|
export { GeminiCliDriver } from './cli-adapters/gemini-driver.js';
|
|
@@ -266,6 +266,15 @@ export class LanAccessDshProxy {
|
|
|
266
266
|
}
|
|
267
267
|
authorize(request, localAddress) {
|
|
268
268
|
const config = this.loginConfig;
|
|
269
|
+
if (request.path === '/__codingns/session' && request.method === 'GET') {
|
|
270
|
+
const token = readCookie(request.headers.cookie, 'dsh_codingns_session');
|
|
271
|
+
const authenticated = !localAddress && config !== null && config.enabled && config.scopes.lan
|
|
272
|
+
&& token !== undefined && !this.revokedSessions.has(token)
|
|
273
|
+
&& verifySignedSessionToken(token, config, 'lan');
|
|
274
|
+
return loginJsonResponse(200, authenticated
|
|
275
|
+
? { authenticated: true, username: config.username }
|
|
276
|
+
: { authenticated: false });
|
|
277
|
+
}
|
|
269
278
|
if (localAddress || config === null || !config.enabled || !config.scopes.lan)
|
|
270
279
|
return 'pass';
|
|
271
280
|
if (request.path === '/__codingns/login' && request.method === 'POST') {
|
|
@@ -280,16 +289,16 @@ export class LanAccessDshProxy {
|
|
|
280
289
|
return loginResponse(303, '', { 'Set-Cookie': sessionCookie(token, config.timeoutSeconds), Location: '/' });
|
|
281
290
|
}
|
|
282
291
|
if (request.path === '/__codingns/logout') {
|
|
283
|
-
const token = readCookie(request.headers.cookie, '
|
|
292
|
+
const token = readCookie(request.headers.cookie, 'dsh_codingns_session');
|
|
284
293
|
if (token !== undefined && verifySignedSessionToken(token, config, 'lan'))
|
|
285
294
|
this.revokedSessions.add(token);
|
|
286
|
-
return loginResponse(303, '', { 'Set-Cookie': '
|
|
295
|
+
return loginResponse(303, '', { 'Set-Cookie': 'dsh_codingns_session=; Path=/; HttpOnly; SameSite=Strict; Max-Age=0', Location: '/' });
|
|
287
296
|
}
|
|
288
297
|
// 浏览器会在页面刷新时独立请求 Web App manifest;它只包含静态元数据,
|
|
289
298
|
// 不应因为登录保护缺少 Cookie 而产生 401 控制台噪声。
|
|
290
299
|
if (request.path === '/manifest.webmanifest' && request.method === 'GET')
|
|
291
300
|
return 'pass';
|
|
292
|
-
const token = readCookie(request.headers.cookie, '
|
|
301
|
+
const token = readCookie(request.headers.cookie, 'dsh_codingns_session');
|
|
293
302
|
if (token !== undefined && !this.revokedSessions.has(token) && verifySignedSessionToken(token, config, 'lan')) {
|
|
294
303
|
return 'pass';
|
|
295
304
|
}
|
|
@@ -389,7 +398,7 @@ function readCookie(value, name) {
|
|
|
389
398
|
return undefined;
|
|
390
399
|
}
|
|
391
400
|
function sessionCookie(token, timeoutSeconds) {
|
|
392
|
-
return `
|
|
401
|
+
return `dsh_codingns_session=${token}; Path=/; HttpOnly; SameSite=Strict; Max-Age=${timeoutSeconds}`;
|
|
393
402
|
}
|
|
394
403
|
function getSetCookie(headers) {
|
|
395
404
|
const extended = headers;
|
|
@@ -398,7 +407,8 @@ function getSetCookie(headers) {
|
|
|
398
407
|
}
|
|
399
408
|
function loginResponse(status, body, extra = {}) {
|
|
400
409
|
const isHtml = body.startsWith('<!doctype html>');
|
|
401
|
-
const
|
|
410
|
+
const isJson = extra['Content-Type']?.startsWith('application/json') === true;
|
|
411
|
+
const content = new TextEncoder().encode(isHtml || isJson ? body : escapeHtml(body));
|
|
402
412
|
const headers = {
|
|
403
413
|
'Content-Type': isHtml ? 'text/html; charset=utf-8' : 'text/plain; charset=utf-8',
|
|
404
414
|
'Content-Length': String(content.length),
|
|
@@ -413,6 +423,9 @@ function loginResponse(status, body, extra = {}) {
|
|
|
413
423
|
const head = encodeLatin1(`HTTP/1.1 ${status} ${statusText(status)}\r\n${Object.entries(headers).map(([key, value]) => `${key}: ${value}`).join('\r\n')}\r\n\r\n`);
|
|
414
424
|
return concatBytes(head, content);
|
|
415
425
|
}
|
|
426
|
+
function loginJsonResponse(status, value) {
|
|
427
|
+
return loginResponse(status, JSON.stringify(value), { 'Content-Type': 'application/json; charset=utf-8' });
|
|
428
|
+
}
|
|
416
429
|
function loginPage() {
|
|
417
430
|
// 视觉规则直接复用 codingns4dsh-h5/styles.css 的 Cyber 登录区,只把 Connect
|
|
418
431
|
// 账号字段替换成本地用户名/密码;不能依赖外部 CSS,避免局域网入口离线时失效。
|
|
@@ -17,6 +17,8 @@ export interface CodingNsNativeToolCall {
|
|
|
17
17
|
readonly callId: string;
|
|
18
18
|
readonly name: string;
|
|
19
19
|
readonly arguments: string;
|
|
20
|
+
/** 外部适配器 ID;旧调用方缺省时保持通用来源标记。 */
|
|
21
|
+
readonly adapterId?: string;
|
|
20
22
|
}
|
|
21
23
|
/** 一次工具调用在 DSH Session 中的稳定位置。 */
|
|
22
24
|
export interface CodingNsNativeToolCallHandle {
|
|
@@ -42,6 +44,7 @@ export interface CodingNsNativeExternalToolEvent {
|
|
|
42
44
|
readonly status: 'running' | 'completed' | 'failed';
|
|
43
45
|
readonly output?: string;
|
|
44
46
|
readonly error?: string;
|
|
47
|
+
readonly adapterId?: string;
|
|
45
48
|
}
|
|
46
49
|
export type CodingNsNativeApprovalOutcome = 'allowed-once' | 'rejected' | 'cancelled' | 'unavailable';
|
|
47
50
|
/** 公共消息投影层交给 DSH 原生权限服务的请求。 */
|
|
@@ -64,6 +67,19 @@ export interface CodingNsNativeRequestContext {
|
|
|
64
67
|
readonly model: string;
|
|
65
68
|
readonly contextWindow?: number;
|
|
66
69
|
}
|
|
70
|
+
/** 外部 Provider 已报告的用量采样;写入 assistant/attempt,不加入模型可见 surface。 */
|
|
71
|
+
export interface CodingNsNativeUsageSample {
|
|
72
|
+
readonly inputTokens: number;
|
|
73
|
+
readonly outputTokens: number;
|
|
74
|
+
readonly cacheReadTokens?: number;
|
|
75
|
+
readonly cacheWriteTokens?: number;
|
|
76
|
+
readonly uncachedInputTokens?: number;
|
|
77
|
+
readonly totalTokens?: number;
|
|
78
|
+
readonly cacheHitRate?: number;
|
|
79
|
+
readonly contextWindow?: number;
|
|
80
|
+
readonly contextTokens?: number;
|
|
81
|
+
readonly contextUsageRatio?: number;
|
|
82
|
+
}
|
|
67
83
|
export interface CodingNsNativeSessionController {
|
|
68
84
|
create?(request: {
|
|
69
85
|
readonly sessionId?: string;
|
|
@@ -112,6 +128,12 @@ export interface CodingNsNativeSessionBridge {
|
|
|
112
128
|
appendExternalToolEvent?(sessionId: string, event: CodingNsNativeExternalToolEvent): boolean;
|
|
113
129
|
/** 写入当前原生步骤的路由上下文元数据,不携带凭据或消息正文。 */
|
|
114
130
|
appendRequestContext?(sessionId: string, context: CodingNsNativeRequestContext): boolean;
|
|
131
|
+
/** 在当前步骤即时记录外部 Provider 用量;该事件不进入模型可见 surface。 */
|
|
132
|
+
appendUsageSample?(sessionId: string, usage: CodingNsNativeUsageSample): boolean;
|
|
133
|
+
/** 判断指定会话是否真的具备下一步注入能力。 */
|
|
134
|
+
canInjectNextStep?(sessionId: string): boolean;
|
|
135
|
+
/** 在当前 Agent turn 的下一个合法 step 注入插件上下文,不唤醒空闲 Agent。 */
|
|
136
|
+
injectNextStep?(sessionId: string, summary?: string): boolean;
|
|
115
137
|
/** 使用 DSH 原生 approval 组件请求一次权限决定;服务不可用时拒绝。 */
|
|
116
138
|
requestApproval?(sessionId: string, request: CodingNsNativeApprovalRequest): Promise<CodingNsNativeApprovalOutcome>;
|
|
117
139
|
/** 使用 DSH 原生 userQuestions 组件提问;服务不可用或取消时返回 null。 */
|
|
@@ -126,5 +148,5 @@ export interface CodingNsNativeSessionBridge {
|
|
|
126
148
|
readonly onFlush?: (session: unknown) => void | Promise<void>;
|
|
127
149
|
}): () => void;
|
|
128
150
|
}
|
|
129
|
-
export declare function createCodingNsNativeSessionBridge(ctx: Context): CodingNsNativeSessionBridge;
|
|
151
|
+
export declare function createCodingNsNativeSessionBridge(ctx: Context, dshVersion?: string): CodingNsNativeSessionBridge;
|
|
130
152
|
//# sourceMappingURL=native-session-bridge.d.ts.map
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
export function createCodingNsNativeSessionBridge(ctx, dshVersion) {
|
|
2
3
|
// Cordis Context 是运行时代理,直接读取未在 inject 中声明的可选服务会抛错。
|
|
3
4
|
// get() 专门用于无强制依赖的服务探测,精简 Host 缺少服务时会返回 undefined。
|
|
4
5
|
const storeValue = ctx.get('sessions');
|
|
@@ -15,11 +16,36 @@ export function createCodingNsNativeSessionBridge(ctx) {
|
|
|
15
16
|
? ctx.on.bind(ctx)
|
|
16
17
|
: undefined;
|
|
17
18
|
const externalHandles = new Map();
|
|
19
|
+
let injectedStepSequence = 0;
|
|
20
|
+
const modernInjectedSource = isModernDshVersion(dshVersion);
|
|
18
21
|
const appendNativeToolCall = (sessionId, call) => {
|
|
19
22
|
const session = appendableSession(store?.get(sessionId));
|
|
20
23
|
const position = session === null ? null : activeStep(session);
|
|
21
24
|
if (session === null || position === null)
|
|
22
25
|
return null;
|
|
26
|
+
// DSH 的工具生命周期由 assistant/message 先声明,再由 tool/call 开始。
|
|
27
|
+
// 外部 Agent 已经在自身进程执行完请求,这条消息只用于持久化声明,绝不触发 DSH 执行器。
|
|
28
|
+
session.append('assistant/message', {
|
|
29
|
+
turn: position.turn,
|
|
30
|
+
step: position.step,
|
|
31
|
+
message: {
|
|
32
|
+
id: `external-tool-${call.callId}-${position.turn}-${position.step}`,
|
|
33
|
+
role: 'assistant',
|
|
34
|
+
content: [{
|
|
35
|
+
type: 'tool-call',
|
|
36
|
+
id: call.callId,
|
|
37
|
+
name: call.name,
|
|
38
|
+
arguments: call.arguments,
|
|
39
|
+
}],
|
|
40
|
+
source: {
|
|
41
|
+
kind: 'model',
|
|
42
|
+
plugin: 'codingns4dsh',
|
|
43
|
+
provider: call.adapterId?.trim() || 'codingns-external',
|
|
44
|
+
model: call.adapterId?.trim() || 'external-agent',
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
stream: [],
|
|
48
|
+
}, { surfaceOp: 'append' });
|
|
23
49
|
const event = session.append('tool/call', {
|
|
24
50
|
turn: position.turn,
|
|
25
51
|
step: position.step,
|
|
@@ -40,14 +66,11 @@ export function createCodingNsNativeSessionBridge(ctx) {
|
|
|
40
66
|
step: handle.step,
|
|
41
67
|
message: {
|
|
42
68
|
id: `${handle.callId}-result-${handle.turn}-${handle.step}`,
|
|
43
|
-
role: '
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
toolCallId: handle.callId,
|
|
47
|
-
content: [{ type: 'text', text: result.output }],
|
|
48
|
-
...(result.isError ? { isError: true } : {}),
|
|
49
|
-
}],
|
|
69
|
+
role: 'tool',
|
|
70
|
+
toolCallId: handle.callId,
|
|
71
|
+
content: [{ type: 'text', text: result.output }],
|
|
50
72
|
source: { kind: 'tool', callId: handle.callId },
|
|
73
|
+
...(result.isError ? { isError: true } : {}),
|
|
51
74
|
},
|
|
52
75
|
...(result.isError
|
|
53
76
|
? { error: { name: 'ExternalToolError', code: 'EXTERNAL_TOOL_FAILED', ...(error ? { reason: error } : {}) } }
|
|
@@ -64,10 +87,69 @@ export function createCodingNsNativeSessionBridge(ctx) {
|
|
|
64
87
|
if (session === null || context.provider.trim() === '' || context.model.trim() === '')
|
|
65
88
|
return false;
|
|
66
89
|
try {
|
|
90
|
+
// request/context 是 token-meter 的容量来源。相同路由重复追加会让
|
|
91
|
+
// 投影先清空旧 pressure,再等待下一条 usage,ContextMeter 因而闪烁。
|
|
92
|
+
// 保留已有容量并跳过等价事件,让用量更新直接落到同一个组件上。
|
|
93
|
+
const previous = latestRequestContext(session);
|
|
94
|
+
if (previous !== null
|
|
95
|
+
&& previous.provider === context.provider
|
|
96
|
+
&& previous.model === context.model
|
|
97
|
+
&& (context.contextWindow === undefined || previous.contextWindow === context.contextWindow))
|
|
98
|
+
return true;
|
|
99
|
+
// Registry 在一轮开始时只能提供适配器身份,不能提供 Provider 容量。
|
|
100
|
+
// 继承上一条已知容量,避免先写无容量事件导致 ContextMeter 卸载;
|
|
101
|
+
// 真正的 usage 到达后,投影器会用 Provider 的最新容量覆盖它。
|
|
102
|
+
const contextWindow = context.contextWindow ?? previous?.contextWindow;
|
|
67
103
|
session.append('request/context', {
|
|
68
104
|
provider: context.provider,
|
|
69
105
|
model: context.model,
|
|
70
|
-
...(
|
|
106
|
+
...(contextWindow === undefined ? {} : { contextWindow }),
|
|
107
|
+
});
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
const appendNativeUsageSample = (sessionId, usage) => {
|
|
115
|
+
const session = appendableSession(store?.get(sessionId));
|
|
116
|
+
const position = session === null ? null : activeStep(session);
|
|
117
|
+
if (session === null || position === null)
|
|
118
|
+
return false;
|
|
119
|
+
try {
|
|
120
|
+
session.append('assistant/attempt', {
|
|
121
|
+
turn: position.turn,
|
|
122
|
+
step: position.step,
|
|
123
|
+
stream: [{
|
|
124
|
+
type: 'chunk',
|
|
125
|
+
time: Date.now(),
|
|
126
|
+
chunk: {
|
|
127
|
+
type: 'usage',
|
|
128
|
+
usage: compactUsage(usage),
|
|
129
|
+
},
|
|
130
|
+
}],
|
|
131
|
+
});
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
const injectNativeNextStep = (sessionId, summary = '外部工具已完成,继续处理当前任务。') => {
|
|
139
|
+
const agent = nativeAgent(ctx, sessionId);
|
|
140
|
+
if (agent === null || typeof agent.inject !== 'function')
|
|
141
|
+
return false;
|
|
142
|
+
injectedStepSequence += 1;
|
|
143
|
+
const boundedSummary = summary.trim().slice(0, 120) || '外部工具已完成,继续处理当前任务。';
|
|
144
|
+
try {
|
|
145
|
+
;
|
|
146
|
+
agent.inject({
|
|
147
|
+
id: `codingns-external-step-${injectedStepSequence}-${randomUUID()}`,
|
|
148
|
+
role: 'user',
|
|
149
|
+
content: [{ type: 'text', text: boundedSummary }],
|
|
150
|
+
source: modernInjectedSource
|
|
151
|
+
? { kind: 'model-selection', form: 'notice', summary: boundedSummary }
|
|
152
|
+
: { kind: 'plugin', plugin: 'codingns4dsh', form: 'notice', summary: boundedSummary },
|
|
71
153
|
});
|
|
72
154
|
return true;
|
|
73
155
|
}
|
|
@@ -75,6 +157,10 @@ export function createCodingNsNativeSessionBridge(ctx) {
|
|
|
75
157
|
return false;
|
|
76
158
|
}
|
|
77
159
|
};
|
|
160
|
+
const canInjectNativeNextStep = (sessionId) => {
|
|
161
|
+
const agent = nativeAgent(ctx, sessionId);
|
|
162
|
+
return agent !== null && typeof agent.inject === 'function';
|
|
163
|
+
};
|
|
78
164
|
return {
|
|
79
165
|
get available() {
|
|
80
166
|
return store !== undefined || controller !== undefined || currentWorkspaceController() !== undefined;
|
|
@@ -133,9 +219,18 @@ export function createCodingNsNativeSessionBridge(ctx) {
|
|
|
133
219
|
appendRequestContext(sessionId, context) {
|
|
134
220
|
return appendNativeRequestContext(sessionId, context);
|
|
135
221
|
},
|
|
222
|
+
appendUsageSample(sessionId, usage) {
|
|
223
|
+
return appendNativeUsageSample(sessionId, usage);
|
|
224
|
+
},
|
|
225
|
+
canInjectNextStep(sessionId) {
|
|
226
|
+
return canInjectNativeNextStep(sessionId);
|
|
227
|
+
},
|
|
228
|
+
injectNextStep(sessionId, summary) {
|
|
229
|
+
return injectNativeNextStep(sessionId, summary);
|
|
230
|
+
},
|
|
136
231
|
appendExternalToolEvent(sessionId, externalTool) {
|
|
137
232
|
try {
|
|
138
|
-
//
|
|
233
|
+
// 兼容旧调用方;声明 assistant 工具生命周期,但绝不伪造 assistant/attempt 结算。
|
|
139
234
|
const key = `${sessionId}:${externalTool.callId}`;
|
|
140
235
|
if (externalTool.phase === 'start') {
|
|
141
236
|
if (externalHandles.has(key))
|
|
@@ -144,6 +239,7 @@ export function createCodingNsNativeSessionBridge(ctx) {
|
|
|
144
239
|
callId: externalTool.callId,
|
|
145
240
|
name: externalTool.name,
|
|
146
241
|
arguments: externalTool.arguments,
|
|
242
|
+
...(externalTool.adapterId === undefined ? {} : { adapterId: externalTool.adapterId }),
|
|
147
243
|
});
|
|
148
244
|
if (handle === null)
|
|
149
245
|
return false;
|
|
@@ -240,6 +336,32 @@ function appendableSession(value) {
|
|
|
240
336
|
return null;
|
|
241
337
|
return value;
|
|
242
338
|
}
|
|
339
|
+
function latestRequestContext(session) {
|
|
340
|
+
let events;
|
|
341
|
+
try {
|
|
342
|
+
events = session.snapshotEvents();
|
|
343
|
+
}
|
|
344
|
+
catch {
|
|
345
|
+
return null;
|
|
346
|
+
}
|
|
347
|
+
for (let index = events.length - 1; index >= 0; index -= 1) {
|
|
348
|
+
const candidate = events[index];
|
|
349
|
+
const event = isRecord(candidate) ? candidate : null;
|
|
350
|
+
if (event?.type !== 'request/context')
|
|
351
|
+
continue;
|
|
352
|
+
const data = isRecord(event.data) ? event.data : null;
|
|
353
|
+
if (typeof data?.provider !== 'string' || typeof data.model !== 'string')
|
|
354
|
+
return null;
|
|
355
|
+
return {
|
|
356
|
+
provider: data.provider,
|
|
357
|
+
model: data.model,
|
|
358
|
+
...(typeof data.contextWindow === 'number' && Number.isFinite(data.contextWindow) && data.contextWindow > 0
|
|
359
|
+
? { contextWindow: data.contextWindow }
|
|
360
|
+
: {}),
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
return null;
|
|
364
|
+
}
|
|
243
365
|
function activeStep(session) {
|
|
244
366
|
let events;
|
|
245
367
|
try {
|
|
@@ -271,6 +393,20 @@ function eventSeq(value) {
|
|
|
271
393
|
function finiteInteger(value) {
|
|
272
394
|
return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0 ? value : null;
|
|
273
395
|
}
|
|
396
|
+
function compactUsage(usage) {
|
|
397
|
+
return {
|
|
398
|
+
inputTokens: usage.inputTokens,
|
|
399
|
+
outputTokens: usage.outputTokens,
|
|
400
|
+
...(usage.cacheReadTokens === undefined ? {} : { cacheReadTokens: usage.cacheReadTokens }),
|
|
401
|
+
...(usage.cacheWriteTokens === undefined ? {} : { cacheWriteTokens: usage.cacheWriteTokens }),
|
|
402
|
+
...(usage.uncachedInputTokens === undefined ? {} : { uncachedInputTokens: usage.uncachedInputTokens }),
|
|
403
|
+
...(usage.totalTokens === undefined ? {} : { totalTokens: usage.totalTokens }),
|
|
404
|
+
...(usage.cacheHitRate === undefined ? {} : { cacheHitRate: usage.cacheHitRate }),
|
|
405
|
+
...(usage.contextWindow === undefined ? {} : { contextWindow: usage.contextWindow }),
|
|
406
|
+
...(usage.contextTokens === undefined ? {} : { contextTokens: usage.contextTokens }),
|
|
407
|
+
...(usage.contextUsageRatio === undefined ? {} : { contextUsageRatio: usage.contextUsageRatio }),
|
|
408
|
+
};
|
|
409
|
+
}
|
|
274
410
|
function isSessionStore(value) {
|
|
275
411
|
return isRecord(value) && typeof value.get === 'function' && typeof value.list === 'function';
|
|
276
412
|
}
|
|
@@ -283,6 +419,17 @@ function isWorkspaceController(value) {
|
|
|
283
419
|
function isRecord(value) {
|
|
284
420
|
return typeof value === 'object' && value !== null;
|
|
285
421
|
}
|
|
422
|
+
function isModernDshVersion(value) {
|
|
423
|
+
if (value === undefined)
|
|
424
|
+
return false;
|
|
425
|
+
const match = /^(\d+)\.(\d+)\.(\d+)/u.exec(value.trim());
|
|
426
|
+
if (match === null)
|
|
427
|
+
return false;
|
|
428
|
+
const major = Number(match[1]);
|
|
429
|
+
const minor = Number(match[2]);
|
|
430
|
+
const patch = Number(match[3]);
|
|
431
|
+
return major > 0 || minor > 1 || minor === 1 && patch >= 7;
|
|
432
|
+
}
|
|
286
433
|
function nativeAgent(ctx, sessionId) {
|
|
287
434
|
const value = ctx.get('agents');
|
|
288
435
|
if (!isRecord(value) || typeof value.get !== 'function')
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* 每个功能模块在启动时登记自己的命名空间,主 handler 只做一次 `namespace/action`
|
|
5
5
|
* 前缀解析。新增模块只登记新命名空间,不需要修改中心分发代码。
|
|
6
6
|
*/
|
|
7
|
-
export type CodingNsRpcHandler = (action: string, payload: unknown) => unknown | Promise<unknown>;
|
|
7
|
+
export type CodingNsRpcHandler = (action: string, payload: unknown, context?: unknown) => unknown | Promise<unknown>;
|
|
8
8
|
export interface CodingNsRpcTarget {
|
|
9
9
|
readonly handler: CodingNsRpcHandler;
|
|
10
10
|
readonly action: string;
|