dsh-cliworker-now 0.0.0-stage → 0.7.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.en.md +364 -0
- package/README.md +368 -2
- package/cordis.patch.yml +3 -0
- package/lib/account-models.mjs +262 -0
- package/lib/client.js +22139 -0
- package/lib/client.js.map +1 -0
- package/lib/grok-catalog.mjs +145 -0
- package/lib/hermes-native-entry.py +96 -0
- package/lib/hermes-nous-refresh.py +331 -0
- package/lib/index.js +14544 -0
- package/lib/index.js.map +1 -0
- package/lib/native-launch.mjs +234 -0
- package/lib/native-spawn.mjs +32 -0
- package/lib/own-account-lease.mjs +105 -0
- package/lib/pi-installation.mjs +87 -0
- package/lib/pi-login.mjs +80 -0
- package/lib/pi-native-catalog.mjs +417 -0
- package/lib/pi-omp-bridge.mjs +602 -0
- package/lib/pi-omp-environment.mjs +15 -0
- package/lib/pi-omp-refresh.mjs +324 -0
- package/lib/private-launch.mjs +23 -0
- package/lib/terminal-bridge.mjs +18 -0
- package/lib/typert.host.d.ts +3 -0
- package/lib/typert.host.js +1430 -0
- package/lib/typert.remote-client.d.ts +72 -0
- package/lib/typert.remote-client.d.ts.map +1 -0
- package/lib/typert.remote-client.js +1256 -0
- package/lib/types/client/account-query-queue.d.ts +16 -0
- package/lib/types/client/account-query-queue.js +61 -0
- package/lib/types/client/account-query-queue.js.map +1 -0
- package/lib/types/client/account-terminal-css.d.ts +1 -0
- package/lib/types/client/account-terminal-css.js +3 -0
- package/lib/types/client/account-terminal-css.js.map +1 -0
- package/lib/types/client/account-terminal.d.ts +17 -0
- package/lib/types/client/account-terminal.js +525 -0
- package/lib/types/client/account-terminal.js.map +1 -0
- package/lib/types/client/assets/antigravity.png +0 -0
- package/lib/types/client/assets/claude-code.png +0 -0
- package/lib/types/client/assets/cliworker-now-logo.png +0 -0
- package/lib/types/client/assets/codex.png +0 -0
- package/lib/types/client/assets/grok.png +0 -0
- package/lib/types/client/assets/hermes.png +0 -0
- package/lib/types/client/assets/kimi-dark.png +0 -0
- package/lib/types/client/assets/kimi-light.png +0 -0
- package/lib/types/client/assets/mimo-code.png +0 -0
- package/lib/types/client/assets/omp.png +0 -0
- package/lib/types/client/assets/opencode.png +0 -0
- package/lib/types/client/assets/pi.png +0 -0
- package/lib/types/client/assets/zcode.png +0 -0
- package/lib/types/client/composer-keymap.d.ts +18 -0
- package/lib/types/client/composer-keymap.js +49 -0
- package/lib/types/client/composer-keymap.js.map +1 -0
- package/lib/types/client/conversation-timeline.d.ts +6 -0
- package/lib/types/client/conversation-timeline.js +65 -0
- package/lib/types/client/conversation-timeline.js.map +1 -0
- package/lib/types/client/copy-text.d.ts +5 -0
- package/lib/types/client/copy-text.js +45 -0
- package/lib/types/client/copy-text.js.map +1 -0
- package/lib/types/client/icons.d.ts +21 -0
- package/lib/types/client/icons.js +68 -0
- package/lib/types/client/icons.js.map +1 -0
- package/lib/types/client/index.d.ts +3 -0
- package/lib/types/client/index.js +124 -0
- package/lib/types/client/index.js.map +1 -0
- package/lib/types/client/management-styles.d.ts +1 -0
- package/lib/types/client/management-styles.js +17 -0
- package/lib/types/client/management-styles.js.map +1 -0
- package/lib/types/client/name-copy.d.ts +5 -0
- package/lib/types/client/name-copy.js +107 -0
- package/lib/types/client/name-copy.js.map +1 -0
- package/lib/types/client/native-job-overlay.d.ts +11 -0
- package/lib/types/client/native-job-overlay.js +129 -0
- package/lib/types/client/native-job-overlay.js.map +1 -0
- package/lib/types/client/operation-error.d.ts +2 -0
- package/lib/types/client/operation-error.js +12 -0
- package/lib/types/client/operation-error.js.map +1 -0
- package/lib/types/client/panel.d.ts +8 -0
- package/lib/types/client/panel.js +310 -0
- package/lib/types/client/panel.js.map +1 -0
- package/lib/types/client/rename-copy-styles.d.ts +1 -0
- package/lib/types/client/rename-copy-styles.js +21 -0
- package/lib/types/client/rename-copy-styles.js.map +1 -0
- package/lib/types/client/rename-worker.d.ts +9 -0
- package/lib/types/client/rename-worker.js +53 -0
- package/lib/types/client/rename-worker.js.map +1 -0
- package/lib/types/client/role-presets.d.ts +6 -0
- package/lib/types/client/role-presets.js +111 -0
- package/lib/types/client/role-presets.js.map +1 -0
- package/lib/types/client/settings-dialog.d.ts +13 -0
- package/lib/types/client/settings-dialog.js +442 -0
- package/lib/types/client/settings-dialog.js.map +1 -0
- package/lib/types/client/stat-popover.d.ts +10 -0
- package/lib/types/client/stat-popover.js +32 -0
- package/lib/types/client/stat-popover.js.map +1 -0
- package/lib/types/client/styles.d.ts +9 -0
- package/lib/types/client/styles.js +221 -0
- package/lib/types/client/styles.js.map +1 -0
- package/lib/types/client/telemetry.d.ts +11 -0
- package/lib/types/client/telemetry.js +24 -0
- package/lib/types/client/telemetry.js.map +1 -0
- package/lib/types/client/worker-card.d.ts +10 -0
- package/lib/types/client/worker-card.js +75 -0
- package/lib/types/client/worker-card.js.map +1 -0
- package/lib/types/client/worker-model-menu.d.ts +9 -0
- package/lib/types/client/worker-model-menu.js +136 -0
- package/lib/types/client/worker-model-menu.js.map +1 -0
- package/lib/types/client/workers.d.ts +21 -0
- package/lib/types/client/workers.js +59 -0
- package/lib/types/client/workers.js.map +1 -0
- package/lib/types/client/zcode-login-link-provider.d.ts +9 -0
- package/lib/types/client/zcode-login-link-provider.js +105 -0
- package/lib/types/client/zcode-login-link-provider.js.map +1 -0
- package/lib/types/client/zcode-login-link.d.ts +16 -0
- package/lib/types/client/zcode-login-link.js +194 -0
- package/lib/types/client/zcode-login-link.js.map +1 -0
- package/lib/types/host/account-identity.d.ts +16 -0
- package/lib/types/host/account-identity.js +126 -0
- package/lib/types/host/account-identity.js.map +1 -0
- package/lib/types/host/account-login.d.ts +10 -0
- package/lib/types/host/account-login.js +126 -0
- package/lib/types/host/account-login.js.map +1 -0
- package/lib/types/host/account-models.d.mts +21 -0
- package/lib/types/host/account-models.mjs +262 -0
- package/lib/types/host/accounts.d.ts +42 -0
- package/lib/types/host/accounts.js +945 -0
- package/lib/types/host/accounts.js.map +1 -0
- package/lib/types/host/adapters.d.ts +24 -0
- package/lib/types/host/adapters.js +380 -0
- package/lib/types/host/adapters.js.map +1 -0
- package/lib/types/host/agy-context.d.ts +8 -0
- package/lib/types/host/agy-context.js +122 -0
- package/lib/types/host/agy-context.js.map +1 -0
- package/lib/types/host/agy-models.d.ts +5 -0
- package/lib/types/host/agy-models.js +37 -0
- package/lib/types/host/agy-models.js.map +1 -0
- package/lib/types/host/agy-windows-account.d.ts +14 -0
- package/lib/types/host/agy-windows-account.js +104 -0
- package/lib/types/host/agy-windows-account.js.map +1 -0
- package/lib/types/host/authorized-catalog.d.ts +14 -0
- package/lib/types/host/authorized-catalog.js +35 -0
- package/lib/types/host/authorized-catalog.js.map +1 -0
- package/lib/types/host/bridge-protocol.d.ts +15 -0
- package/lib/types/host/bridge-protocol.js +80 -0
- package/lib/types/host/bridge-protocol.js.map +1 -0
- package/lib/types/host/claude-native-oauth.d.ts +17 -0
- package/lib/types/host/claude-native-oauth.js +272 -0
- package/lib/types/host/claude-native-oauth.js.map +1 -0
- package/lib/types/host/claude-own-route.d.ts +33 -0
- package/lib/types/host/claude-own-route.js +250 -0
- package/lib/types/host/claude-own-route.js.map +1 -0
- package/lib/types/host/cli-account-binding.d.ts +33 -0
- package/lib/types/host/cli-account-binding.js +540 -0
- package/lib/types/host/cli-account-binding.js.map +1 -0
- package/lib/types/host/cli-protocol.d.ts +27 -0
- package/lib/types/host/cli-protocol.js +212 -0
- package/lib/types/host/cli-protocol.js.map +1 -0
- package/lib/types/host/codex-account.d.ts +8 -0
- package/lib/types/host/codex-account.js +143 -0
- package/lib/types/host/codex-account.js.map +1 -0
- package/lib/types/host/codex-models.d.ts +6 -0
- package/lib/types/host/codex-models.js +169 -0
- package/lib/types/host/codex-models.js.map +1 -0
- package/lib/types/host/extended-adapters.d.ts +44 -0
- package/lib/types/host/extended-adapters.js +207 -0
- package/lib/types/host/extended-adapters.js.map +1 -0
- package/lib/types/host/first-party-account-context.d.ts +26 -0
- package/lib/types/host/first-party-account-context.js +55 -0
- package/lib/types/host/first-party-account-context.js.map +1 -0
- package/lib/types/host/first-party-models.d.ts +29 -0
- package/lib/types/host/first-party-models.js +459 -0
- package/lib/types/host/first-party-models.js.map +1 -0
- package/lib/types/host/grok-adapter.d.ts +44 -0
- package/lib/types/host/grok-adapter.js +293 -0
- package/lib/types/host/grok-adapter.js.map +1 -0
- package/lib/types/host/grok-models.d.ts +47 -0
- package/lib/types/host/grok-models.js +320 -0
- package/lib/types/host/grok-models.js.map +1 -0
- package/lib/types/host/harness-opencode-accounts.d.ts +17 -0
- package/lib/types/host/harness-opencode-accounts.js +80 -0
- package/lib/types/host/harness-opencode-accounts.js.map +1 -0
- package/lib/types/host/hermes-account-context.d.ts +8 -0
- package/lib/types/host/hermes-account-context.js +99 -0
- package/lib/types/host/hermes-account-context.js.map +1 -0
- package/lib/types/host/hermes-accounts.d.ts +19 -0
- package/lib/types/host/hermes-accounts.js +356 -0
- package/lib/types/host/hermes-accounts.js.map +1 -0
- package/lib/types/host/hermes-adapter.d.ts +93 -0
- package/lib/types/host/hermes-adapter.js +455 -0
- package/lib/types/host/hermes-adapter.js.map +1 -0
- package/lib/types/host/hermes-env.d.ts +4 -0
- package/lib/types/host/hermes-env.js +22 -0
- package/lib/types/host/hermes-env.js.map +1 -0
- package/lib/types/host/hermes-installation.d.ts +10 -0
- package/lib/types/host/hermes-installation.js +181 -0
- package/lib/types/host/hermes-installation.js.map +1 -0
- package/lib/types/host/hermes-models.d.ts +26 -0
- package/lib/types/host/hermes-models.js +328 -0
- package/lib/types/host/hermes-models.js.map +1 -0
- package/lib/types/host/hermes-native-entry.py +96 -0
- package/lib/types/host/hermes-nous-refresh.py +331 -0
- package/lib/types/host/hermes-nous.d.ts +53 -0
- package/lib/types/host/hermes-nous.js +343 -0
- package/lib/types/host/hermes-nous.js.map +1 -0
- package/lib/types/host/hermes-renewal.d.ts +27 -0
- package/lib/types/host/hermes-renewal.js +292 -0
- package/lib/types/host/hermes-renewal.js.map +1 -0
- package/lib/types/host/hermes-suppression.d.ts +7 -0
- package/lib/types/host/hermes-suppression.js +69 -0
- package/lib/types/host/hermes-suppression.js.map +1 -0
- package/lib/types/host/hermes-windows-installation.d.ts +5 -0
- package/lib/types/host/hermes-windows-installation.js +91 -0
- package/lib/types/host/hermes-windows-installation.js.map +1 -0
- package/lib/types/host/index.d.ts +140 -0
- package/lib/types/host/index.js +947 -0
- package/lib/types/host/index.js.map +1 -0
- package/lib/types/host/kimi-accounts.d.ts +17 -0
- package/lib/types/host/kimi-accounts.js +220 -0
- package/lib/types/host/kimi-accounts.js.map +1 -0
- package/lib/types/host/kimi-oauth-models.d.ts +14 -0
- package/lib/types/host/kimi-oauth-models.js +246 -0
- package/lib/types/host/kimi-oauth-models.js.map +1 -0
- package/lib/types/host/managed-agent.d.ts +4 -0
- package/lib/types/host/managed-agent.js +127 -0
- package/lib/types/host/managed-agent.js.map +1 -0
- package/lib/types/host/mimo-configuration.d.ts +22 -0
- package/lib/types/host/mimo-configuration.js +258 -0
- package/lib/types/host/mimo-configuration.js.map +1 -0
- package/lib/types/host/mimo-metadata-cache.d.ts +22 -0
- package/lib/types/host/mimo-metadata-cache.js +121 -0
- package/lib/types/host/mimo-metadata-cache.js.map +1 -0
- package/lib/types/host/native-capability-cache.d.ts +11 -0
- package/lib/types/host/native-capability-cache.js +94 -0
- package/lib/types/host/native-capability-cache.js.map +1 -0
- package/lib/types/host/native-launch.d.mts +2 -0
- package/lib/types/host/native-launch.mjs +234 -0
- package/lib/types/host/native-process.d.ts +5 -0
- package/lib/types/host/native-process.js +41 -0
- package/lib/types/host/native-process.js.map +1 -0
- package/lib/types/host/native-spawn.mjs +32 -0
- package/lib/types/host/opencode-adapter.d.ts +94 -0
- package/lib/types/host/opencode-adapter.js +507 -0
- package/lib/types/host/opencode-adapter.js.map +1 -0
- package/lib/types/host/opencode-native.d.ts +27 -0
- package/lib/types/host/opencode-native.js +403 -0
- package/lib/types/host/opencode-native.js.map +1 -0
- package/lib/types/host/own-account-lease.d.mts +5 -0
- package/lib/types/host/own-account-lease.mjs +105 -0
- package/lib/types/host/pi-installation.d.mts +7 -0
- package/lib/types/host/pi-installation.mjs +87 -0
- package/lib/types/host/pi-omp-accounts.d.ts +28 -0
- package/lib/types/host/pi-omp-accounts.js +175 -0
- package/lib/types/host/pi-omp-accounts.js.map +1 -0
- package/lib/types/host/pi-omp-adapter.d.ts +32 -0
- package/lib/types/host/pi-omp-adapter.js +190 -0
- package/lib/types/host/pi-omp-adapter.js.map +1 -0
- package/lib/types/host/pi-omp-environment.d.mts +1 -0
- package/lib/types/host/pi-omp-environment.mjs +15 -0
- package/lib/types/host/pi-omp-identity.d.ts +2 -0
- package/lib/types/host/pi-omp-identity.js +142 -0
- package/lib/types/host/pi-omp-identity.js.map +1 -0
- package/lib/types/host/pi-omp-logout.d.ts +3 -0
- package/lib/types/host/pi-omp-logout.js +152 -0
- package/lib/types/host/pi-omp-logout.js.map +1 -0
- package/lib/types/host/pi-omp-native.d.ts +71 -0
- package/lib/types/host/pi-omp-native.js +753 -0
- package/lib/types/host/pi-omp-native.js.map +1 -0
- package/lib/types/host/pi-omp-refresh.d.mts +7 -0
- package/lib/types/host/pi-omp-refresh.mjs +324 -0
- package/lib/types/host/private-launch.mjs +23 -0
- package/lib/types/host/process.d.ts +43 -0
- package/lib/types/host/process.js +134 -0
- package/lib/types/host/process.js.map +1 -0
- package/lib/types/host/protocol.d.ts +23 -0
- package/lib/types/host/protocol.js +112 -0
- package/lib/types/host/protocol.js.map +1 -0
- package/lib/types/host/roles.d.ts +34 -0
- package/lib/types/host/roles.js +80 -0
- package/lib/types/host/roles.js.map +1 -0
- package/lib/types/host/routing.d.ts +31 -0
- package/lib/types/host/routing.js +248 -0
- package/lib/types/host/routing.js.map +1 -0
- package/lib/types/host/runtime.d.ts +60 -0
- package/lib/types/host/runtime.js +598 -0
- package/lib/types/host/runtime.js.map +1 -0
- package/lib/types/host/storage.d.ts +48 -0
- package/lib/types/host/storage.js +449 -0
- package/lib/types/host/storage.js.map +1 -0
- package/lib/types/host/telemetry.d.ts +17 -0
- package/lib/types/host/telemetry.js +158 -0
- package/lib/types/host/telemetry.js.map +1 -0
- package/lib/types/host/windows-account-bootstrap.ps1 +44 -0
- package/lib/types/host/windows-account-launch.mjs +47 -0
- package/lib/types/host/windows-account-owner.ps1 +137 -0
- package/lib/types/host/windows-account-stdio.mjs +19 -0
- package/lib/types/host/windows-account-terminal.d.ts +17 -0
- package/lib/types/host/windows-account-terminal.js +208 -0
- package/lib/types/host/windows-account-terminal.js.map +1 -0
- package/lib/types/host/windows-agy-account.ps1 +81 -0
- package/lib/types/host/windows-cli-installation.d.ts +31 -0
- package/lib/types/host/windows-cli-installation.js +157 -0
- package/lib/types/host/windows-cli-installation.js.map +1 -0
- package/lib/types/host/windows-hidden-launch.mjs +49 -0
- package/lib/types/host/windows-hidden-process.d.ts +12 -0
- package/lib/types/host/windows-hidden-process.js +116 -0
- package/lib/types/host/windows-hidden-process.js.map +1 -0
- package/lib/types/host/zcode-account-models.d.ts +16 -0
- package/lib/types/host/zcode-account-models.js +114 -0
- package/lib/types/host/zcode-account-models.js.map +1 -0
- package/lib/types/host/zcode-adapter.d.ts +93 -0
- package/lib/types/host/zcode-adapter.js +808 -0
- package/lib/types/host/zcode-adapter.js.map +1 -0
- package/lib/types/host/zcode-grok-accounts.d.ts +30 -0
- package/lib/types/host/zcode-grok-accounts.js +408 -0
- package/lib/types/host/zcode-grok-accounts.js.map +1 -0
- package/lib/types/shared/accounts.d.ts +47 -0
- package/lib/types/shared/accounts.js +2 -0
- package/lib/types/shared/accounts.js.map +1 -0
- package/lib/types/shared/builtin-presets.d.ts +2 -0
- package/lib/types/shared/builtin-presets.js +231 -0
- package/lib/types/shared/builtin-presets.js.map +1 -0
- package/lib/types/shared/cli-settings.d.ts +5 -0
- package/lib/types/shared/cli-settings.js +2 -0
- package/lib/types/shared/cli-settings.js.map +1 -0
- package/lib/types/shared/model-presentation.d.ts +10 -0
- package/lib/types/shared/model-presentation.js +95 -0
- package/lib/types/shared/model-presentation.js.map +1 -0
- package/lib/types/shared/models.d.ts +7 -0
- package/lib/types/shared/models.js +35 -0
- package/lib/types/shared/models.js.map +1 -0
- package/lib/types/shared/telemetry.d.ts +18 -0
- package/lib/types/shared/telemetry.js +16 -0
- package/lib/types/shared/telemetry.js.map +1 -0
- package/lib/types/shared/types.d.ts +127 -0
- package/lib/types/shared/types.js +147 -0
- package/lib/types/shared/types.js.map +1 -0
- package/lib/windows-account-bootstrap.ps1 +44 -0
- package/lib/windows-account-launch.mjs +47 -0
- package/lib/windows-account-owner.ps1 +137 -0
- package/lib/windows-account-stdio.mjs +19 -0
- package/lib/windows-agy-account.ps1 +81 -0
- package/lib/windows-hidden-launch.mjs +49 -0
- package/lib/zcode-resume.mjs +423 -0
- package/package.json +109 -4
|
@@ -0,0 +1,808 @@
|
|
|
1
|
+
import { mkdirSync, chmodSync, writeFileSync, existsSync, readSync, openSync, closeSync, fstatSync, constants, lstatSync, renameSync, rmSync, } from 'node:fs';
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
import { join, dirname, basename, resolve } from 'node:path';
|
|
4
|
+
import { homedir } from 'node:os';
|
|
5
|
+
import { StringDecoder } from 'node:string_decoder';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { EFFORTS } from "../shared/types.js";
|
|
8
|
+
import { probeAccountModels } from './account-models.mjs';
|
|
9
|
+
import { readZCodeAccountApiKeys, readZCodeAccountBindings } from "./zcode-account-models.js";
|
|
10
|
+
// Native ZCode uses exact tool-name sets, not globs. Deny its own delegation
|
|
11
|
+
// surface and bundled browser REPL. This is not a general MCP isolation policy;
|
|
12
|
+
// arbitrary MCP tool names cannot be safely represented by "mcp__*" here.
|
|
13
|
+
export const ZCODE_DENIED_TOOLS = [
|
|
14
|
+
'Agent',
|
|
15
|
+
'Task',
|
|
16
|
+
'Skill',
|
|
17
|
+
'TaskOutput',
|
|
18
|
+
'TaskStop',
|
|
19
|
+
'SendMessage',
|
|
20
|
+
'ReadSessionContext',
|
|
21
|
+
'CreateWorkflow',
|
|
22
|
+
'AmendWorkflow',
|
|
23
|
+
'SaveWorkflow',
|
|
24
|
+
'EvalWorkflowSnippet',
|
|
25
|
+
'ListWorkflowRuns',
|
|
26
|
+
'GetWorkflowRun',
|
|
27
|
+
'ResumeWorkflowRun',
|
|
28
|
+
'ResolveWorkflowQuestion',
|
|
29
|
+
'ListSavedWorkflows',
|
|
30
|
+
'ListModels',
|
|
31
|
+
'mcp__node_repl__js',
|
|
32
|
+
];
|
|
33
|
+
const record = (value) => value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
34
|
+
const nonempty = (value) => typeof value === 'string' && !!value.trim();
|
|
35
|
+
/** Login and every worker share auth; sessions, logs and model choices stay isolated. */
|
|
36
|
+
export function zcodeAuthDirectory(configured, stateDirectory) {
|
|
37
|
+
return (configured ??
|
|
38
|
+
join(stateDirectory ?? join(process.env.DSH_HOME ?? join(homedir(), '.dsh'), 'cliworker-now'), 'accounts', 'zcode'));
|
|
39
|
+
}
|
|
40
|
+
/** A complete, version-controlled CLI can be deployed here without relying on /tmp. */
|
|
41
|
+
export function managedZCodeEntry(home = homedir()) {
|
|
42
|
+
return join(home, '.local/share/cliworker-now/runtimes/zcode/cli/zcode.cjs');
|
|
43
|
+
}
|
|
44
|
+
function builtinPath(executable, builtin) {
|
|
45
|
+
const adjacent = join(dirname(executable), 'provider/zcode-builtin.json');
|
|
46
|
+
// Both Desktop bundles keep glm/zcode.cjs next to config/provider resources.
|
|
47
|
+
const bundled = join(dirname(executable), '../config/provider/zcode-builtin.json');
|
|
48
|
+
const config = builtin ??
|
|
49
|
+
(existsSync(adjacent)
|
|
50
|
+
? adjacent
|
|
51
|
+
: existsSync(bundled)
|
|
52
|
+
? bundled
|
|
53
|
+
: '/Applications/ZCode.app/Contents/Resources/config/provider/zcode-builtin.json');
|
|
54
|
+
if (!existsSync(config))
|
|
55
|
+
throw new Error('请配置与 ZCode CLI 配套的 zcodeBuiltinConfig');
|
|
56
|
+
return config;
|
|
57
|
+
}
|
|
58
|
+
export function zcodeEnvironment(executable, state, auth, builtin) {
|
|
59
|
+
for (const dir of [state, join(state, 'storage'), join(state, 'logs'), join(state, 'tmp')]) {
|
|
60
|
+
// CLI tools can write their own state; do not follow a planted link on the next run.
|
|
61
|
+
let info;
|
|
62
|
+
try {
|
|
63
|
+
info = lstatSync(dir);
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
if (error.code !== 'ENOENT')
|
|
67
|
+
throw error;
|
|
68
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
69
|
+
info = lstatSync(dir);
|
|
70
|
+
}
|
|
71
|
+
if (!info.isDirectory() || info.isSymbolicLink())
|
|
72
|
+
throw new Error('ZCode state directory must not be a symlink');
|
|
73
|
+
chmodSync(dir, 0o700);
|
|
74
|
+
}
|
|
75
|
+
// Harness deliberately scrubs parent SECRET variables. Native authentication,
|
|
76
|
+
// metadata decryption and resumed/headless tasks must use the same cipher key.
|
|
77
|
+
// Keep it exclusively in the selected ZCode child's environment.
|
|
78
|
+
const credentialSecret = process.env.ZCODE_CREDENTIAL_SECRET?.trim();
|
|
79
|
+
return {
|
|
80
|
+
...(credentialSecret ? { ZCODE_CREDENTIAL_SECRET: credentialSecret } : {}),
|
|
81
|
+
ZCODE_DATA_BASE_DIR: auth ?? zcodeAuthDirectory(),
|
|
82
|
+
ZCODE_STORAGE_DIR: join(state, 'storage'),
|
|
83
|
+
ZCODE_SESSION_DB_PATH: join(state, 'storage/session.sqlite'),
|
|
84
|
+
ZCODE_LOG_DIR: join(state, 'logs'),
|
|
85
|
+
ZCODE_PERSONAL_PROVIDER_CONFIG_FILE: join(state, 'personal.json'),
|
|
86
|
+
ZCODE_BUILTIN_PROVIDER_CONFIG_FILE: builtinPath(executable, builtin),
|
|
87
|
+
TMPDIR: join(state, 'tmp'),
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function writePersonalConfig(path, value) {
|
|
91
|
+
const temporary = join(dirname(path), `.personal-${randomUUID()}.tmp`);
|
|
92
|
+
try {
|
|
93
|
+
writeFileSync(temporary, JSON.stringify(value), { flag: 'wx', mode: 0o600 });
|
|
94
|
+
// rename replaces an existing symlink itself; never chmod/write its target.
|
|
95
|
+
renameSync(temporary, path);
|
|
96
|
+
}
|
|
97
|
+
finally {
|
|
98
|
+
rmSync(temporary, { force: true });
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
export async function prepareZCode(input) {
|
|
102
|
+
const builtin = readZCodeConfig(builtinPath(input.executable, input.builtinConfig), false);
|
|
103
|
+
const personal = readZCodePersonal(input.authDirectory, input);
|
|
104
|
+
const selected = resolveZCodeModels(builtin, personal).find((entry) => entry.choice.id === input.preference.model);
|
|
105
|
+
if (!selected)
|
|
106
|
+
throw new Error('ZCode 所选模型不在原生可见目录中');
|
|
107
|
+
if (input.preference.effort !== 'default' && !selected.choice.efforts?.includes(input.preference.effort))
|
|
108
|
+
throw new Error('ZCode 所选强度不受原生模型支持');
|
|
109
|
+
const reasoning = input.preference.effort === 'default'
|
|
110
|
+
? selected.nativeReasoningDefault
|
|
111
|
+
: input.preference.effort === 'none'
|
|
112
|
+
? 'disabled'
|
|
113
|
+
: input.preference.effort;
|
|
114
|
+
const selection = {
|
|
115
|
+
providerId: selected.providerId,
|
|
116
|
+
modelId: selected.modelId,
|
|
117
|
+
...(reasoning ? { options: { reasoningLevel: reasoning } } : {}),
|
|
118
|
+
};
|
|
119
|
+
const env = zcodeEnvironment(input.executable, input.stateDirectory, input.authDirectory, input.builtinConfig);
|
|
120
|
+
// Preserve private provider/model overlays. Only this worker's default selection changes.
|
|
121
|
+
writePersonalConfig(env.ZCODE_PERSONAL_PROVIDER_CONFIG_FILE, {
|
|
122
|
+
...personal,
|
|
123
|
+
config: {
|
|
124
|
+
...personal.config,
|
|
125
|
+
defaultModelSelection: selection,
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
const argv = [
|
|
129
|
+
...(/\.[cm]?js$/.test(input.executable) ? [process.execPath, input.executable] : [input.executable]),
|
|
130
|
+
'--cwd',
|
|
131
|
+
input.project,
|
|
132
|
+
'--mode',
|
|
133
|
+
input.mode === 'plan' ? 'plan' : 'edit',
|
|
134
|
+
'--output-format',
|
|
135
|
+
'stream-json',
|
|
136
|
+
'--disallowedTools',
|
|
137
|
+
ZCODE_DENIED_TOOLS.join(','),
|
|
138
|
+
...(input.conversationId ? ['--resume', input.conversationId] : []),
|
|
139
|
+
'--prompt',
|
|
140
|
+
`任务:\n${input.prompt}`,
|
|
141
|
+
];
|
|
142
|
+
if (input.conversationId) {
|
|
143
|
+
const request = join(input.stateDirectory, `resume-${randomUUID()}.json`);
|
|
144
|
+
writePersonalConfig(request, {
|
|
145
|
+
executable: input.executable,
|
|
146
|
+
argv,
|
|
147
|
+
project: input.project,
|
|
148
|
+
conversationId: input.conversationId,
|
|
149
|
+
selection,
|
|
150
|
+
});
|
|
151
|
+
return {
|
|
152
|
+
argv: [process.execPath, fileURLToPath(new URL('./zcode-resume.mjs', import.meta.url)), request],
|
|
153
|
+
env,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
return { argv, env };
|
|
157
|
+
}
|
|
158
|
+
const BUILTIN_MODEL_GROUPS = [
|
|
159
|
+
'modelRules',
|
|
160
|
+
'modelApiRules',
|
|
161
|
+
'providerSiteRules',
|
|
162
|
+
'templateModelRules',
|
|
163
|
+
'builtinProviderModelRules',
|
|
164
|
+
];
|
|
165
|
+
const exactKey = (rule) => JSON.stringify([rule.providerId, rule.modelId]);
|
|
166
|
+
const nativeId = (value) => nonempty(value) && value.length <= 1024 && !/[\x00-\x1f\x7f]/.test(value);
|
|
167
|
+
const emptyPersonal = () => ({
|
|
168
|
+
schemaVersion: 1,
|
|
169
|
+
config: {
|
|
170
|
+
providerConfigRules: { providerRules: [] },
|
|
171
|
+
modelConfigRules: { providerModelRules: [], manualProviderModelRules: [] },
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
/** Native ConfigOverlay: undefined preserves, null clears, arrays replace. Access types cannot mix. */
|
|
175
|
+
function overlayConfig(base, next) {
|
|
176
|
+
return Object.fromEntries([...new Set([...Object.keys(base), ...Object.keys(next)])].map((key) => {
|
|
177
|
+
const value = next[key];
|
|
178
|
+
if (value === undefined)
|
|
179
|
+
return [key, base[key]];
|
|
180
|
+
if (record(base[key]) && record(value) && !(key === 'access' && base[key].type !== value.type))
|
|
181
|
+
return [key, overlayConfig(base[key], value)];
|
|
182
|
+
return [key, value];
|
|
183
|
+
}));
|
|
184
|
+
}
|
|
185
|
+
function providerRules(value, personal = false) {
|
|
186
|
+
if (!Array.isArray(value))
|
|
187
|
+
throw new Error('Invalid ZCode provider rules');
|
|
188
|
+
const ids = new Set();
|
|
189
|
+
return value.map((rule) => {
|
|
190
|
+
if (!record(rule) ||
|
|
191
|
+
!nativeId(rule.providerId) ||
|
|
192
|
+
!record(rule.config) ||
|
|
193
|
+
ids.has(rule.providerId) ||
|
|
194
|
+
(rule.enabled !== undefined && typeof rule.enabled !== 'boolean') ||
|
|
195
|
+
(rule.templateId != null && !nativeId(rule.templateId)))
|
|
196
|
+
throw new Error('Invalid ZCode provider rule');
|
|
197
|
+
if (personal &&
|
|
198
|
+
('builtinModelIds' in rule.config ||
|
|
199
|
+
(rule.providerId.startsWith('account:') && 'access' in rule.config)))
|
|
200
|
+
throw new Error('Invalid ZCode personal provider overlay');
|
|
201
|
+
ids.add(rule.providerId);
|
|
202
|
+
return rule;
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
function parsePersonal(value) {
|
|
206
|
+
if (!record(value) || value.schemaVersion !== 1 || !record(value.config))
|
|
207
|
+
throw new Error('Unsupported ZCode personal config schema');
|
|
208
|
+
const config = value.config, models = config.modelConfigRules;
|
|
209
|
+
const providers = providerRules(config.providerConfigRules?.providerRules, true);
|
|
210
|
+
if (!record(models) ||
|
|
211
|
+
!Array.isArray(models.providerModelRules) ||
|
|
212
|
+
!Array.isArray(models.manualProviderModelRules))
|
|
213
|
+
throw new Error('Invalid ZCode personal model rules');
|
|
214
|
+
const exact = new Set();
|
|
215
|
+
for (const group of [models.providerModelRules, models.manualProviderModelRules])
|
|
216
|
+
for (const rule of group) {
|
|
217
|
+
if (!record(rule) ||
|
|
218
|
+
!nativeId(rule.providerId) ||
|
|
219
|
+
!nativeId(rule.modelId) ||
|
|
220
|
+
!record(rule.config) ||
|
|
221
|
+
exact.has(exactKey(rule)))
|
|
222
|
+
throw new Error('Invalid or duplicate ZCode personal model rule');
|
|
223
|
+
exact.add(exactKey(rule));
|
|
224
|
+
}
|
|
225
|
+
if (config.providerOrder !== undefined &&
|
|
226
|
+
(!Array.isArray(config.providerOrder) || !config.providerOrder.every(nativeId)))
|
|
227
|
+
throw new Error('Invalid ZCode personal provider order');
|
|
228
|
+
return {
|
|
229
|
+
schemaVersion: 1,
|
|
230
|
+
config: {
|
|
231
|
+
...config,
|
|
232
|
+
providerConfigRules: { providerRules: providers },
|
|
233
|
+
modelConfigRules: {
|
|
234
|
+
providerModelRules: models.providerModelRules,
|
|
235
|
+
manualProviderModelRules: models.manualProviderModelRules,
|
|
236
|
+
},
|
|
237
|
+
},
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
function mergePersonal(documents) {
|
|
241
|
+
const providers = new Map();
|
|
242
|
+
const exact = new Map();
|
|
243
|
+
let config = emptyPersonal().config;
|
|
244
|
+
for (const document of documents) {
|
|
245
|
+
config = { ...config, ...document.config };
|
|
246
|
+
for (const rule of document.config.providerConfigRules.providerRules) {
|
|
247
|
+
const prior = providers.get(rule.providerId);
|
|
248
|
+
providers.set(rule.providerId, prior ? { ...prior, ...rule, config: overlayConfig(prior.config, rule.config) } : rule);
|
|
249
|
+
}
|
|
250
|
+
for (const [manual, rules] of [
|
|
251
|
+
[false, document.config.modelConfigRules.providerModelRules],
|
|
252
|
+
[true, document.config.modelConfigRules.manualProviderModelRules],
|
|
253
|
+
])
|
|
254
|
+
for (const rule of rules)
|
|
255
|
+
exact.set(exactKey(rule), { manual, rule });
|
|
256
|
+
}
|
|
257
|
+
return {
|
|
258
|
+
schemaVersion: 1,
|
|
259
|
+
config: {
|
|
260
|
+
...config,
|
|
261
|
+
providerConfigRules: { providerRules: [...providers.values()] },
|
|
262
|
+
modelConfigRules: {
|
|
263
|
+
providerModelRules: [...exact.values()].filter((entry) => !entry.manual).map((entry) => entry.rule),
|
|
264
|
+
manualProviderModelRules: [...exact.values()]
|
|
265
|
+
.filter((entry) => entry.manual)
|
|
266
|
+
.map((entry) => entry.rule),
|
|
267
|
+
},
|
|
268
|
+
},
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
/** Bounded read of program metadata or private native configuration; never leak parse text. */
|
|
272
|
+
function readZCodeConfig(path, optional, personal = false) {
|
|
273
|
+
let fd;
|
|
274
|
+
const buffer = Buffer.alloc(2 * 1024 * 1024 + 1);
|
|
275
|
+
try {
|
|
276
|
+
if (personal) {
|
|
277
|
+
// The native .zcode/v2 directory entries must not redirect a private read.
|
|
278
|
+
const parent = lstatSync(dirname(path));
|
|
279
|
+
if (!parent.isDirectory() || parent.isSymbolicLink())
|
|
280
|
+
throw new Error('Unsafe personal config directory');
|
|
281
|
+
if (basename(dirname(path)) === 'v2' &&
|
|
282
|
+
basename(dirname(dirname(path))) === '.zcode' &&
|
|
283
|
+
lstatSync(dirname(dirname(path))).isSymbolicLink())
|
|
284
|
+
throw new Error('Unsafe personal config ancestor');
|
|
285
|
+
}
|
|
286
|
+
fd = openSync(path, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
|
|
287
|
+
const before = fstatSync(fd);
|
|
288
|
+
if (!before.isFile() || before.nlink !== 1 || before.size >= buffer.length)
|
|
289
|
+
throw new Error('Unsafe ZCode config file');
|
|
290
|
+
let length = 0;
|
|
291
|
+
while (length < buffer.length) {
|
|
292
|
+
const count = readSync(fd, buffer, length, buffer.length - length, null);
|
|
293
|
+
if (!count)
|
|
294
|
+
break;
|
|
295
|
+
length += count;
|
|
296
|
+
}
|
|
297
|
+
const after = fstatSync(fd);
|
|
298
|
+
if (length >= buffer.length || before.size !== after.size || before.mtimeMs !== after.mtimeMs)
|
|
299
|
+
throw new Error('ZCode config changed during read');
|
|
300
|
+
return JSON.parse(buffer.subarray(0, length).toString('utf8'));
|
|
301
|
+
}
|
|
302
|
+
catch (error) {
|
|
303
|
+
if (optional && error.code === 'ENOENT')
|
|
304
|
+
return undefined;
|
|
305
|
+
throw new Error(personal ? 'ZCode 个人模型配置无法安全读取或解析' : 'ZCode 内置模型目录无法安全读取或解析');
|
|
306
|
+
}
|
|
307
|
+
finally {
|
|
308
|
+
buffer.fill(0);
|
|
309
|
+
if (fd !== undefined)
|
|
310
|
+
closeSync(fd);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
function personalPaths(authDirectory, options = {}) {
|
|
314
|
+
const explicit = options.personalConfig ??
|
|
315
|
+
(options.nativeHome === undefined ? process.env.ZCODE_PERSONAL_PROVIDER_CONFIG_FILE?.trim() : undefined);
|
|
316
|
+
const nativeBase = options.nativeHome ?? process.env.ZCODE_DATA_BASE_DIR?.trim() ?? homedir();
|
|
317
|
+
const paths = new Map([
|
|
318
|
+
[resolve(explicit || join(nativeBase, '.zcode/v2/provider_config.json')), !explicit],
|
|
319
|
+
]);
|
|
320
|
+
const pluginPath = resolve(join(authDirectory ?? zcodeAuthDirectory(), '.zcode/v2/provider_config.json'));
|
|
321
|
+
if (!paths.has(pluginPath))
|
|
322
|
+
paths.set(pluginPath, true);
|
|
323
|
+
return paths;
|
|
324
|
+
}
|
|
325
|
+
function readZCodePersonal(authDirectory, options = {}) {
|
|
326
|
+
const documents = [];
|
|
327
|
+
for (const [path, optional] of personalPaths(authDirectory, options)) {
|
|
328
|
+
const raw = readZCodeConfig(path, optional, true);
|
|
329
|
+
if (raw !== undefined)
|
|
330
|
+
documents.push(parsePersonal(raw));
|
|
331
|
+
}
|
|
332
|
+
return mergePersonal(documents);
|
|
333
|
+
}
|
|
334
|
+
/** Private Host material, using the exact discovery overlay and current-account key binding. */
|
|
335
|
+
export async function readZCodeBindingMaterial(executable, authDirectory, builtinConfig, options = {}) {
|
|
336
|
+
options.signal?.throwIfAborted();
|
|
337
|
+
const candidates = resolveZCodeModels(readZCodeConfig(builtinPath(executable, builtinConfig), false), readZCodePersonal(authDirectory, options));
|
|
338
|
+
const accounts = await readZCodeAccountBindings(authDirectory, candidates.flatMap((entry) => entry.providerConfig.access?.type === 'zhipu-account' ? [entry.providerId] : []), options);
|
|
339
|
+
const credentials = new Map();
|
|
340
|
+
for (const entry of candidates) {
|
|
341
|
+
const { access, api } = entry.providerConfig;
|
|
342
|
+
const account = access?.type === 'zhipu-account' ? accounts.get(entry.providerId) : undefined;
|
|
343
|
+
const key = account?.key ??
|
|
344
|
+
(['api-key', 'zhipu-coding-plan-api-key'].includes(access?.type) ? access.apiKey : undefined);
|
|
345
|
+
if (!nonempty(key))
|
|
346
|
+
continue;
|
|
347
|
+
credentials.set(entry.providerId, {
|
|
348
|
+
provider: entry.providerId,
|
|
349
|
+
key,
|
|
350
|
+
identity: account?.identity,
|
|
351
|
+
baseUrl: api.baseUrl,
|
|
352
|
+
apiType: api.type,
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
options.signal?.throwIfAborted();
|
|
356
|
+
return {
|
|
357
|
+
credentials: [...credentials.values()],
|
|
358
|
+
sourceIds: [
|
|
359
|
+
resolve(authDirectory),
|
|
360
|
+
...[...personalPaths(authDirectory, options)].flatMap(([path, optional]) => readZCodeConfig(path, optional, true) === undefined ? [] : [path]),
|
|
361
|
+
],
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
/** Account evidence is an explicit native API credential, never a catalog entry. */
|
|
365
|
+
export function readZCodePersonalIdentity(authDirectory, options = {}) {
|
|
366
|
+
try {
|
|
367
|
+
const personal = readZCodePersonal(authDirectory, options);
|
|
368
|
+
let unknown = false;
|
|
369
|
+
let configured = false;
|
|
370
|
+
for (const rule of personal.config.providerConfigRules.providerRules) {
|
|
371
|
+
if (rule.enabled === false || rule.config.visibility === 'hidden')
|
|
372
|
+
continue;
|
|
373
|
+
const access = rule.config.access;
|
|
374
|
+
if (access == null)
|
|
375
|
+
continue;
|
|
376
|
+
if (!record(access))
|
|
377
|
+
throw new Error('Invalid ZCode access configuration');
|
|
378
|
+
if (!['api-key', 'zhipu-coding-plan-api-key'].includes(access.type)) {
|
|
379
|
+
unknown = true;
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
382
|
+
if (access.apiKey != null && typeof access.apiKey !== 'string')
|
|
383
|
+
throw new Error('Invalid ZCode API credential');
|
|
384
|
+
if (nonempty(access.apiKey))
|
|
385
|
+
configured = true;
|
|
386
|
+
}
|
|
387
|
+
if (configured)
|
|
388
|
+
return {
|
|
389
|
+
state: 'configured',
|
|
390
|
+
authMethod: 'api',
|
|
391
|
+
verification: 'local',
|
|
392
|
+
summary: '已配置 ZCode API',
|
|
393
|
+
};
|
|
394
|
+
return unknown
|
|
395
|
+
? { state: 'unknown', verification: 'local', summary: '账号配置格式未知' }
|
|
396
|
+
: { state: 'unconfigured', verification: 'local', summary: '尚未配置 ZCode API' };
|
|
397
|
+
}
|
|
398
|
+
catch {
|
|
399
|
+
return { state: 'unavailable', verification: 'local', summary: '账号配置读取失败,请检查配置' };
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
function nativeOrder(base, personal, order = []) {
|
|
403
|
+
const builtin = [...new Set(base)], own = [...new Set(personal)].filter((id) => !builtin.includes(id));
|
|
404
|
+
const known = new Set([...builtin, ...own]), arranged = [...new Set(order)].filter((id) => known.has(id)), moved = new Set(arranged);
|
|
405
|
+
return [...builtin.filter((id) => !moved.has(id)), ...arranged, ...own.filter((id) => !moved.has(id))];
|
|
406
|
+
}
|
|
407
|
+
function clearManualModel(config) {
|
|
408
|
+
const next = structuredClone(config);
|
|
409
|
+
if (record(next.properties)) {
|
|
410
|
+
for (const key of [
|
|
411
|
+
'contextWindow',
|
|
412
|
+
'supportsJsonSchemaOutput',
|
|
413
|
+
'supportsNativeWebSearch',
|
|
414
|
+
'supportsMidConversationSystem',
|
|
415
|
+
])
|
|
416
|
+
delete next.properties[key];
|
|
417
|
+
if (record(next.properties.inputFormat))
|
|
418
|
+
for (const key of ['supportsImage', 'supportsVideo', 'supportsPdf'])
|
|
419
|
+
delete next.properties.inputFormat[key];
|
|
420
|
+
}
|
|
421
|
+
if (record(next.optionSpecs)) {
|
|
422
|
+
delete next.optionSpecs.reasoningLevel;
|
|
423
|
+
if (record(next.optionSpecs.maxOutputTokens))
|
|
424
|
+
delete next.optionSpecs.maxOutputTokens.max;
|
|
425
|
+
}
|
|
426
|
+
return next;
|
|
427
|
+
}
|
|
428
|
+
function resolveZCodeModels(value, personal) {
|
|
429
|
+
if (!record(value) || value.schemaVersion !== 1 || !record(value.config))
|
|
430
|
+
throw new Error('Unsupported ZCode builtin catalog schema');
|
|
431
|
+
const base = providerRules(value.config.providerConfigRules?.providerRules), rules = value.config.modelConfigRules;
|
|
432
|
+
if (!record(rules) || BUILTIN_MODEL_GROUPS.some((key) => !Array.isArray(rules[key])))
|
|
433
|
+
throw new Error('Incomplete ZCode builtin rule groups');
|
|
434
|
+
const templates = new Map();
|
|
435
|
+
for (const template of value.config.providerConfigRules?.templateRules ?? []) {
|
|
436
|
+
if (!record(template) ||
|
|
437
|
+
!nativeId(template.templateId) ||
|
|
438
|
+
!record(template.config) ||
|
|
439
|
+
templates.has(template.templateId))
|
|
440
|
+
throw new Error('Invalid ZCode provider template');
|
|
441
|
+
templates.set(template.templateId, template.config);
|
|
442
|
+
}
|
|
443
|
+
const providers = new Map();
|
|
444
|
+
const withTemplate = (rule) => {
|
|
445
|
+
const template = rule.templateId == null ? undefined : templates.get(rule.templateId);
|
|
446
|
+
if (rule.templateId != null && !template)
|
|
447
|
+
throw new Error('Missing ZCode provider template');
|
|
448
|
+
return { ...rule, config: template ? overlayConfig(template, rule.config) : rule.config };
|
|
449
|
+
};
|
|
450
|
+
for (const rule of base)
|
|
451
|
+
providers.set(rule.providerId, withTemplate(rule));
|
|
452
|
+
for (const rule of personal.config.providerConfigRules.providerRules) {
|
|
453
|
+
const prior = providers.get(rule.providerId);
|
|
454
|
+
providers.set(rule.providerId, prior ? { ...prior, ...rule, config: overlayConfig(prior.config, rule.config) } : withTemplate(rule));
|
|
455
|
+
}
|
|
456
|
+
const match = (pattern, text, insensitive = false) => {
|
|
457
|
+
if (!nonempty(pattern) || pattern.length > 4096)
|
|
458
|
+
throw new Error('Invalid ZCode model rule');
|
|
459
|
+
try {
|
|
460
|
+
return new RegExp(`^(?:${pattern})$`, insensitive ? 'i' : undefined).test(text);
|
|
461
|
+
}
|
|
462
|
+
catch {
|
|
463
|
+
throw new Error('Invalid ZCode model rule pattern');
|
|
464
|
+
}
|
|
465
|
+
};
|
|
466
|
+
const choices = new Map();
|
|
467
|
+
const providerIds = nativeOrder(base.map((rule) => rule.providerId), personal.config.providerConfigRules.providerRules.map((rule) => rule.providerId), personal.config.providerOrder);
|
|
468
|
+
for (const providerId of providerIds) {
|
|
469
|
+
const provider = providers.get(providerId), config = provider.config;
|
|
470
|
+
if (provider.enabled === false || config.visibility === 'hidden')
|
|
471
|
+
continue;
|
|
472
|
+
const builtinIds = config.builtinModelIds ?? [], personalIds = config.personalModelIds ?? [], modelOrder = config.modelOrder ?? [];
|
|
473
|
+
if (![builtinIds, personalIds, modelOrder].every((ids) => Array.isArray(ids) && ids.every(nativeId)))
|
|
474
|
+
throw new Error('Invalid ZCode model membership');
|
|
475
|
+
if (!record(config.api) ||
|
|
476
|
+
!['anthropic-messages', 'openai-chat-completions', 'openai-responses'].includes(config.api.type) ||
|
|
477
|
+
!nonempty(config.api.baseUrl))
|
|
478
|
+
throw new Error('Invalid ZCode provider API');
|
|
479
|
+
let endpoint;
|
|
480
|
+
try {
|
|
481
|
+
endpoint = new URL(config.api.baseUrl);
|
|
482
|
+
}
|
|
483
|
+
catch {
|
|
484
|
+
throw new Error('Invalid ZCode provider API URL');
|
|
485
|
+
}
|
|
486
|
+
const suffix = `${endpoint.search}${endpoint.hash}`, serialized = endpoint.toString();
|
|
487
|
+
const baseUrl = `${(suffix ? serialized.slice(0, -suffix.length) : serialized).replace(/\/+$/, '')}${suffix}`;
|
|
488
|
+
for (const modelId of nativeOrder(builtinIds, personalIds, modelOrder)) {
|
|
489
|
+
let model = {};
|
|
490
|
+
const apply = (rule, manual = false) => {
|
|
491
|
+
model = overlayConfig(manual ? clearManualModel(model) : model, rule.config);
|
|
492
|
+
};
|
|
493
|
+
for (const key of BUILTIN_MODEL_GROUPS)
|
|
494
|
+
for (const rule of rules[key]) {
|
|
495
|
+
if (!record(rule) || !record(rule.config))
|
|
496
|
+
throw new Error('Invalid ZCode builtin model rule');
|
|
497
|
+
if (key === 'builtinProviderModelRules') {
|
|
498
|
+
if (rule.providerId !== providerId || rule.modelId !== modelId)
|
|
499
|
+
continue;
|
|
500
|
+
}
|
|
501
|
+
else if (key === 'templateModelRules') {
|
|
502
|
+
if (rule.templateId !== provider.templateId || rule.modelId !== modelId)
|
|
503
|
+
continue;
|
|
504
|
+
}
|
|
505
|
+
else {
|
|
506
|
+
if (!match(rule.modelMatch, modelId, true))
|
|
507
|
+
continue;
|
|
508
|
+
if ((key === 'modelApiRules' || key === 'providerSiteRules') &&
|
|
509
|
+
rule.apiTypeMatch !== undefined &&
|
|
510
|
+
!match(rule.apiTypeMatch, config.api.type))
|
|
511
|
+
continue;
|
|
512
|
+
if (key === 'providerSiteRules' && !match(rule.baseUrlMatch, baseUrl))
|
|
513
|
+
continue;
|
|
514
|
+
}
|
|
515
|
+
apply(rule);
|
|
516
|
+
}
|
|
517
|
+
for (const rule of personal.config.modelConfigRules.providerModelRules)
|
|
518
|
+
if (rule.providerId === providerId && rule.modelId === modelId)
|
|
519
|
+
apply(rule);
|
|
520
|
+
for (const rule of personal.config.modelConfigRules.manualProviderModelRules)
|
|
521
|
+
if (rule.providerId === providerId && rule.modelId === modelId)
|
|
522
|
+
apply(rule, true);
|
|
523
|
+
if (model.enabled !== undefined && typeof model.enabled !== 'boolean')
|
|
524
|
+
throw new Error('Invalid ZCode model enabled rule');
|
|
525
|
+
if (model.enabled !== true)
|
|
526
|
+
continue;
|
|
527
|
+
const values = model.optionSpecs?.reasoningLevel?.values;
|
|
528
|
+
if (values != null && (!Array.isArray(values) || !values.every(nonempty)))
|
|
529
|
+
throw new Error('Invalid ZCode model reasoning choices');
|
|
530
|
+
// Native enabled has no numeric effort meaning; keep native default rather than inventing low/high.
|
|
531
|
+
const mapped = Array.isArray(values)
|
|
532
|
+
? values.flatMap((level) => level === 'disabled'
|
|
533
|
+
? ['none']
|
|
534
|
+
: level === 'enabled'
|
|
535
|
+
? ['default']
|
|
536
|
+
: EFFORTS.includes(level)
|
|
537
|
+
? [level]
|
|
538
|
+
: [])
|
|
539
|
+
: [];
|
|
540
|
+
const id = `${providerId}/${modelId}`;
|
|
541
|
+
if (choices.has(id))
|
|
542
|
+
throw new Error('Ambiguous ZCode provider/model ID');
|
|
543
|
+
choices.set(id, {
|
|
544
|
+
providerId,
|
|
545
|
+
modelId,
|
|
546
|
+
nativeReasoningDefault: Array.isArray(values) ? values.at(-1) : undefined,
|
|
547
|
+
providerConfig: config,
|
|
548
|
+
choice: {
|
|
549
|
+
id,
|
|
550
|
+
label: `${modelId}(${providerId} · 本机目录)`,
|
|
551
|
+
efforts: [...new Set(mapped.length ? mapped : ['default'])],
|
|
552
|
+
},
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
return [...choices.values()];
|
|
557
|
+
}
|
|
558
|
+
/** Public projection contains only original model/provider identifiers and proven reasoning choices. */
|
|
559
|
+
export function parseZCodeBuiltin(value, personal) {
|
|
560
|
+
return resolveZCodeModels(value, personal === undefined ? emptyPersonal() : parsePersonal(personal)).map((entry) => entry.choice);
|
|
561
|
+
}
|
|
562
|
+
// Exact canonical IDs from ZCode 0.16.9's official-glm-model-id.ts. The native
|
|
563
|
+
// account metadata returns lowercase aliases, while execution keeps these IDs.
|
|
564
|
+
// Unknown spellings/suffixes remain exact; this is not general case folding.
|
|
565
|
+
const officialGlmIds = new Map([
|
|
566
|
+
'GLM-5.3',
|
|
567
|
+
'GLM-5.3-Flash',
|
|
568
|
+
'GLM-5V-Turbo',
|
|
569
|
+
'GLM-5.2',
|
|
570
|
+
'GLM-5.1',
|
|
571
|
+
'GLM-5.1-Highspeed',
|
|
572
|
+
'GLM-5',
|
|
573
|
+
'GLM-5-Turbo',
|
|
574
|
+
'GLM-4.7',
|
|
575
|
+
'GLM-4.7-FlashX',
|
|
576
|
+
'GLM-4.7-Flash',
|
|
577
|
+
'GLM-4.6',
|
|
578
|
+
'GLM-4.5-Air',
|
|
579
|
+
'GLM-4.5',
|
|
580
|
+
'GLM-4.6V',
|
|
581
|
+
'GLM-4.6V-Flash',
|
|
582
|
+
'GLM-4.6V-FlashX',
|
|
583
|
+
'GLM-4.1V-Thinking-FlashX',
|
|
584
|
+
'GLM-4.1V-Thinking-Flash',
|
|
585
|
+
'GLM-4-FlashX-250414',
|
|
586
|
+
'GLM-4-Flash-250414',
|
|
587
|
+
'GLM-4V-Flash',
|
|
588
|
+
].map((id) => [id.toLowerCase(), id]));
|
|
589
|
+
function usesOfficialGlmAliases(entry) {
|
|
590
|
+
const { access, api } = entry.providerConfig;
|
|
591
|
+
if (access.type !== 'zhipu-account' ||
|
|
592
|
+
access.mode !== 'individual-coding-plan' ||
|
|
593
|
+
api.type !== 'anthropic-messages')
|
|
594
|
+
return false;
|
|
595
|
+
const baseUrl = api.baseUrl.replace(/\/+$/, '');
|
|
596
|
+
return ((entry.providerId === 'account:bigmodel-individual-coding-plan' &&
|
|
597
|
+
access.accountType === 'bigmodel' &&
|
|
598
|
+
baseUrl === 'https://open.bigmodel.cn/api/anthropic') ||
|
|
599
|
+
(entry.providerId === 'account:zai-individual-coding-plan' &&
|
|
600
|
+
access.accountType === 'zai' &&
|
|
601
|
+
baseUrl === 'https://api.z.ai/api/anthropic'));
|
|
602
|
+
}
|
|
603
|
+
export async function discoverZCode(executable, _capture, _stateDirectory, authDirectory, builtinConfig, options = {}) {
|
|
604
|
+
options.signal?.throwIfAborted();
|
|
605
|
+
const personal = readZCodePersonal(authDirectory, options);
|
|
606
|
+
const candidates = resolveZCodeModels(readZCodeConfig(builtinPath(executable, builtinConfig), false), personal);
|
|
607
|
+
const bound = await readZCodeAccountApiKeys(authDirectory ?? zcodeAuthDirectory(), candidates.flatMap((entry) => {
|
|
608
|
+
const access = entry.providerConfig.access;
|
|
609
|
+
return access?.type === 'zhipu-account' &&
|
|
610
|
+
access.mode === 'individual-coding-plan' &&
|
|
611
|
+
['bigmodel', 'zai'].includes(access.accountType)
|
|
612
|
+
? [entry.providerId]
|
|
613
|
+
: [];
|
|
614
|
+
}), options);
|
|
615
|
+
const groups = new Map();
|
|
616
|
+
for (const entry of candidates) {
|
|
617
|
+
const { access, api } = entry.providerConfig;
|
|
618
|
+
// Native OAuth login binds a concrete Worker API key to the current account.
|
|
619
|
+
// Only that exact binding enters the same native route; static entitled flags,
|
|
620
|
+
// old identities, desktop OAuth tokens and refresh tokens do not substitute.
|
|
621
|
+
const apiKey = access?.type === 'zhipu-account'
|
|
622
|
+
? bound.get(entry.providerId)
|
|
623
|
+
: ['api-key', 'zhipu-coding-plan-api-key'].includes(access?.type)
|
|
624
|
+
? access.apiKey
|
|
625
|
+
: undefined;
|
|
626
|
+
if (!nonempty(apiKey))
|
|
627
|
+
continue;
|
|
628
|
+
// Custom headers may alter both credential and scope. Until this query can
|
|
629
|
+
// mirror the native route exactly, keep that route out of the public list.
|
|
630
|
+
if (record(api.headers) && Object.keys(api.headers).length)
|
|
631
|
+
continue;
|
|
632
|
+
const group = groups.get(entry.providerId) ?? [];
|
|
633
|
+
group.push(entry);
|
|
634
|
+
groups.set(entry.providerId, group);
|
|
635
|
+
}
|
|
636
|
+
const results = await Promise.all([...groups.values()].map(async (entries) => {
|
|
637
|
+
const { access, api } = entries[0].providerConfig;
|
|
638
|
+
const secret = access.type === 'zhipu-account' ? bound.get(entries[0].providerId) : access.apiKey;
|
|
639
|
+
const scope = await probeAccountModels({
|
|
640
|
+
provider: entries[0].providerId,
|
|
641
|
+
credential: { type: 'api', key: secret },
|
|
642
|
+
baseUrl: api.baseUrl,
|
|
643
|
+
apiType: api.type,
|
|
644
|
+
// Native createAnthropic adds x-api-key, while ZCode's factory also
|
|
645
|
+
// supplies withAnthropicAuthorizationHeader for the same bound key.
|
|
646
|
+
...(api.type === 'anthropic-messages' ? { anthropicAuth: 'api-key-and-bearer' } : {}),
|
|
647
|
+
verifiedModelIds: [],
|
|
648
|
+
}, { ...options.probeOptions, signal: options.signal ?? options.probeOptions?.signal });
|
|
649
|
+
if (scope.state !== 'supported')
|
|
650
|
+
return [];
|
|
651
|
+
const officialAliases = usesOfficialGlmAliases(entries[0]);
|
|
652
|
+
return entries.flatMap(({ modelId, choice }) => {
|
|
653
|
+
const supported = scope.models.find((entry) => entry.id === modelId ||
|
|
654
|
+
(officialAliases && officialGlmIds.get(entry.id.toLowerCase()) === modelId));
|
|
655
|
+
if (!supported || choice.id.includes(secret) || choice.label.includes(secret))
|
|
656
|
+
return [];
|
|
657
|
+
return [
|
|
658
|
+
{
|
|
659
|
+
...choice,
|
|
660
|
+
cost: access.type !== 'api-key' && supported.cost === 'free' ? 'unknown' : supported.cost,
|
|
661
|
+
},
|
|
662
|
+
];
|
|
663
|
+
});
|
|
664
|
+
}));
|
|
665
|
+
options.signal?.throwIfAborted();
|
|
666
|
+
return results.flat();
|
|
667
|
+
}
|
|
668
|
+
export class ZCodeProtocol {
|
|
669
|
+
emit;
|
|
670
|
+
identify;
|
|
671
|
+
maxLineBytes;
|
|
672
|
+
expectedModel;
|
|
673
|
+
decoder = new StringDecoder('utf8');
|
|
674
|
+
pending = '';
|
|
675
|
+
steps = new Map();
|
|
676
|
+
open = new Set();
|
|
677
|
+
toolNames = new Map();
|
|
678
|
+
failed = false;
|
|
679
|
+
completed = false;
|
|
680
|
+
ended = false;
|
|
681
|
+
conversationId;
|
|
682
|
+
result;
|
|
683
|
+
constructor(emit, identify, maxLineBytes, expectedModel) {
|
|
684
|
+
this.emit = emit;
|
|
685
|
+
this.identify = identify;
|
|
686
|
+
this.maxLineBytes = maxLineBytes;
|
|
687
|
+
this.expectedModel = expectedModel;
|
|
688
|
+
}
|
|
689
|
+
feed(chunk) {
|
|
690
|
+
if (this.ended)
|
|
691
|
+
throw new Error('ZCode stream already ended');
|
|
692
|
+
this.pending += typeof chunk === 'string' ? chunk : this.decoder.write(chunk);
|
|
693
|
+
let n;
|
|
694
|
+
while ((n = this.pending.indexOf('\n')) >= 0) {
|
|
695
|
+
const line = this.pending.slice(0, n).trim();
|
|
696
|
+
this.pending = this.pending.slice(n + 1);
|
|
697
|
+
if (line)
|
|
698
|
+
this.line(line);
|
|
699
|
+
}
|
|
700
|
+
if (Buffer.byteLength(this.pending) > this.maxLineBytes)
|
|
701
|
+
throw new Error('ZCode event too large');
|
|
702
|
+
}
|
|
703
|
+
end() {
|
|
704
|
+
if (this.ended)
|
|
705
|
+
return;
|
|
706
|
+
this.ended = true;
|
|
707
|
+
this.pending += this.decoder.end();
|
|
708
|
+
if (this.pending.trim())
|
|
709
|
+
this.line(this.pending.trim());
|
|
710
|
+
this.pending = '';
|
|
711
|
+
}
|
|
712
|
+
step(id) {
|
|
713
|
+
if (!this.steps.has(id))
|
|
714
|
+
this.steps.set(id, this.steps.size);
|
|
715
|
+
return this.steps.get(id);
|
|
716
|
+
}
|
|
717
|
+
line(line) {
|
|
718
|
+
if (Buffer.byteLength(line) > this.maxLineBytes)
|
|
719
|
+
throw new Error('ZCode event too large');
|
|
720
|
+
let value;
|
|
721
|
+
try {
|
|
722
|
+
value = JSON.parse(line);
|
|
723
|
+
}
|
|
724
|
+
catch {
|
|
725
|
+
throw new Error('Invalid ZCode stream-json event');
|
|
726
|
+
}
|
|
727
|
+
if (!record(value) || !nonempty(value.type) || this.result)
|
|
728
|
+
throw new Error('Unexpected ZCode event');
|
|
729
|
+
const v = value;
|
|
730
|
+
const p = record(v.payload) ? v.payload : {};
|
|
731
|
+
if (nonempty(v.sessionId)) {
|
|
732
|
+
if (this.conversationId && this.conversationId !== v.sessionId)
|
|
733
|
+
throw new Error('ZCode session changed');
|
|
734
|
+
if (!this.conversationId) {
|
|
735
|
+
this.conversationId = v.sessionId;
|
|
736
|
+
this.identify(v.sessionId);
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
if (v.type === 'model.streaming' && p.kind === 'text_delta') {
|
|
740
|
+
if (!nonempty(p.assistantMessageId) || typeof p.delta !== 'string')
|
|
741
|
+
throw new Error('Invalid ZCode text delta');
|
|
742
|
+
this.emit({ kind: 'assistant', step: this.step(p.assistantMessageId), text: p.delta });
|
|
743
|
+
}
|
|
744
|
+
else if (v.type === 'session.updated' && nonempty(p.providerId) && nonempty(p.modelId)) {
|
|
745
|
+
if (this.expectedModel && `${p.providerId}/${p.modelId}` !== this.expectedModel)
|
|
746
|
+
throw new Error('ZCode 实际模型与所选模型不匹配,任务已拒绝');
|
|
747
|
+
this.emit({ kind: 'status', text: 'ZCode 模型已确认', observedModel: `${p.providerId}/${p.modelId}` });
|
|
748
|
+
}
|
|
749
|
+
else if (v.type === 'tool.updated') {
|
|
750
|
+
if (p.kind === 'batch') {
|
|
751
|
+
// Native permission rejection may only emit scheduled + batch(errorCount),
|
|
752
|
+
// with no started/result event. Never let turn.completed erase that fact.
|
|
753
|
+
if (!Number.isSafeInteger(p.errorCount) || p.errorCount < 0)
|
|
754
|
+
throw new Error('Invalid ZCode tool batch');
|
|
755
|
+
if (p.errorCount > 0)
|
|
756
|
+
this.failed = true;
|
|
757
|
+
}
|
|
758
|
+
else if (['scheduled', 'started', 'result'].includes(p.kind)) {
|
|
759
|
+
if (!nonempty(p.toolCallId))
|
|
760
|
+
throw new Error('Invalid ZCode tool identity');
|
|
761
|
+
const done = p.kind === 'result';
|
|
762
|
+
if (done) {
|
|
763
|
+
this.open.delete(p.toolCallId);
|
|
764
|
+
if (p.result?.success !== true)
|
|
765
|
+
this.failed = true;
|
|
766
|
+
}
|
|
767
|
+
else
|
|
768
|
+
this.open.add(p.toolCallId);
|
|
769
|
+
if (nonempty(p.toolName))
|
|
770
|
+
this.toolNames.set(p.toolCallId, p.toolName);
|
|
771
|
+
this.emit({
|
|
772
|
+
kind: 'tool',
|
|
773
|
+
step: this.step(p.toolCallId),
|
|
774
|
+
text: this.toolNames.get(p.toolCallId) ?? '工具',
|
|
775
|
+
state: done ? (p.result?.success === true ? 'COMPLETED' : 'FAILED') : 'RUNNING',
|
|
776
|
+
detail: JSON.stringify(p.result ?? p),
|
|
777
|
+
});
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
else if (v.type === 'permission.resolved' &&
|
|
781
|
+
(p.decision === 'deny' || p.decision?.behavior === 'deny' || p.resolution === 'deny')) {
|
|
782
|
+
this.failed = true;
|
|
783
|
+
this.emit({ kind: 'diagnostic', text: 'ZCode 权限请求被拒绝' });
|
|
784
|
+
}
|
|
785
|
+
else if (v.type === 'turn.failed' || v.type === 'error') {
|
|
786
|
+
this.failed = true;
|
|
787
|
+
this.emit({ kind: 'diagnostic', text: 'ZCode 执行失败', detail: JSON.stringify(p) });
|
|
788
|
+
}
|
|
789
|
+
else if (v.type === 'turn.completed') {
|
|
790
|
+
this.completed = p.resultType === 'success';
|
|
791
|
+
if (!this.completed)
|
|
792
|
+
this.failed = true;
|
|
793
|
+
}
|
|
794
|
+
else if (v.type === 'result') {
|
|
795
|
+
if (!this.conversationId || !nonempty(v.sessionId) || typeof v.response !== 'string')
|
|
796
|
+
throw new Error('ZCode result missing session/text');
|
|
797
|
+
const status = this.completed && !this.failed && !this.open.size ? 'SUCCESS' : 'ERROR';
|
|
798
|
+
this.result = {
|
|
799
|
+
conversationId: this.conversationId,
|
|
800
|
+
status,
|
|
801
|
+
response: v.response,
|
|
802
|
+
...(status === 'ERROR' ? { error: 'ZCode 未成功完成,存在失败工具、权限拒绝或缺失终态' } : {}),
|
|
803
|
+
};
|
|
804
|
+
this.emit({ kind: 'result', text: v.response, state: status });
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
//# sourceMappingURL=zcode-adapter.js.map
|